管理类的实例数

本文关键字:实例 管理 | 更新日期: 2023-09-27 18:27:09

我有一个类B,我从中生成大量实例来加快优化问题中的一些搜索。这个数字变得如此之大,以至于我经常产生OutOfMemory异常。作为解决方法,我每x秒减少一次实例数量,但我想做一些更明智的事情。为此,我想知道:

  1. 管理"活动"(已创建但尚未垃圾收集)实例数量的好方法是什么

  2. 更技术性的:我如何估计我的实例必须使用(比如)大约一半的RAM?

管理类的实例数

首先,我会尽可能减少每个对象的内存占用。由于您创建了大量的对象,其中许多对象可能具有相似的属性,这使它们成为蝇量级模式的完美候选者。根据维基百科的文章,一个经典的例子是文字处理:

轻量级模式的一个典型用法是在字处理器中用图形表示字符的数据结构。对于文档中的每个字符,可能需要一个包含其字体轮廓、字体度量和其他格式数据的字形对象,但对于每个字符来说,这将达到数百或数千个字节。相反,对于每个字符,可能都有对文档中相同字符的每个实例共享的轻量级字形对象的引用;只有每个字符的位置(在文档和/或页面中)需要在内部存储。

作为第二步,我将估计单个对象的大小。在这种情况下,我强调估计,因为在C#中获取实际大小并不容易。然后,这个估计可以用于设置最大数量的N对象,您可以在不遇到OutOfMemoryException的情况下安全地实例化这些对象。

您可以通过每次创建或销毁对象时更新对象计数器(例如)来跟踪(大约)有多少对象是活动的,从而利用这些信息

class Foo {
    private static NumberOfInstances = 0;
    public Foo() {
        NumberOfInstances++;
    }
    ~Foo() {
        NumberOfInstances--;
    }
}

如果线程安全是一个问题,那么这个实现当然需要稍微改进一下。

编辑:正如mikez在评论中指出的,在这种情况下,通过终结器实现这一点可能会导致严重的性能问题。因此,实现IDisposable并在Dispose操作中执行递减可能会更好。然而,这具有的缺点是可能忘记处理对象。然而,我怀疑这对你来说会是一个严重的问题。

我不知道第二个问题的答案,但第一个问题的回答可能是:

  • 使用WeakReference.IsAlive属性
  • 从析构函数发送事件

听起来你想保留尽可能多的已经计算好的数据,以便以后访问。也许.NET 4.0中引入的MemoryCache类对你的情况会有所帮助。

你可以这样做:

var cache = new MemoryCache("PathCache", new NameValueCollection()
{
  { "CacheMemoryLimitMegabytes", "256" }, // max 256 MB
  { "PhysicalMemoryLimit", "50" } // max 50% of RAM
});
// cache an item
cache["MyPath"] = "...";
// check, whether the cache contains an item
if (cache.Contains("MyPath"))
{
  // cache hit!
  var cachedPath = cache["MyPath"];
}
// ensure cache is released somewhere in your code
cache.Dispose();

每个节点扩展都应该查询数据,并且不要将所有对象数据存储在内存中,只存储每个节点的定义参数。选择节点时,显示查询中的数据。

您可以使用工厂模式来创建实例,从而跟踪它们并管理您的内存