4

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

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

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

4

5 回答 5

5

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

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

第二步,我会估计单个对象的大小。我强调在这种情况下进行估计,因为在 C# 中获得实际大小并不容易。然后可以使用此估计来设置N您可以安全实例化而不会遇到OutOfMemoryException.

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

class Foo {

    private static NumberOfInstances = 0;

    public Foo() {
        NumberOfInstances++;
    }

    ~Foo() {
        NumberOfInstances--;
    }
}

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

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

于 2013-08-11T18:21:14.070 回答
2

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

于 2013-08-11T17:39:09.013 回答
2

听起来您希望尽可能多地保留已计算的数据以供以后访问。也许 .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();
于 2013-08-12T07:06:09.440 回答
0

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

于 2013-08-11T17:44:14.193 回答
0

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

于 2013-08-12T07:21:46.380 回答