为包含图标的类创建许多实例时出现OutOfMemoryException

时间:2013-04-17 09:11:38

标签: c# winforms

我有一个包含图像的类:

class AnyClass
{
    Image AnyImage;
    string AnyString;
}

当我创建超过2000个此类的实例时,我有一个OutOfMemoryException 要分配给AnyClass的图片只有3个图标大小 这些实例将作为ListView的数据源。

有没有办法在AnyClass中通过引用分配图像?
或者处理这种情况的方式/模式是什么?

EDITED


尚未测试代码,但这与正在进行的操作类似:

static void Main(string[] args)
{
    List<AnyClass> lst = new List<AnyClass>();
    for (int i = 0; i < 2000; i++)
    {
        lst.Add(new AnyClass() { AnyImage = ImageList.image1, AnyString = "test" });
    }
}

public class AnyClass
{
    public Image AnyImage;
    public string AnyString;
}

public class ImageList
{
    public static Image image1;
    public static Image image2;
    public static Image imgae3;
}

2 个答案:

答案 0 :(得分:1)

我在资源项目中添加了一个示例图像,我已经编写了两个代码:

这个抛出记忆异常:

List<AnyClass> lst = new List<AnyClass>();
for (int i = 0; i < 20000; i++)
{
    lst.Add(new AnyClass() { AnyImage = ConsoleApplication1.Properties.Resources.Image1, AnyString = "test" });
}

这个没有:

var image1 = ConsoleApplication1.Properties.Resources.Image1;
List<AnyClass> lst = new List<AnyClass>();
for (int i = 0; i < 20000; i++)
{
    lst.Add(new AnyClass() { AnyImage = image1, AnyString = "test" });
}

在任务管理器中,您可以看到第一个代码正在使用内存,除非没有更多内容 第二个代码立即运行。

此外,您可以尝试以下代码:

var instance1 = ConsoleApplication1.Properties.Resources.Image1;
var instance2 = ConsoleApplication1.Properties.Resources.Image1;

Console.Write(instance1 == instance2); -- output false

因此,如果您在项目的资源中使用图像,则必须先将其缓存,否则每次调用资源时都会创建一个新的图像实例。

答案 1 :(得分:0)

听起来这与GDI +句柄有关,而非内存。特别是,我希望你完成时不会处理图像。由于AnyClass封装了图片,感觉AnyClass应为IDisposable

class AnyClass : IDisposable
{
    public void Dispose() {
        if(AnyImage != null) { AnyImage.Dispose(); AnyImage = null; }
    }
    Image AnyImage;
    string AnyString;
}

然后你应该在完成任何此类实例后处理(最好通过using)。

这里的要点是每个Image都使用GDI +句柄;该句柄在以下任何一个时释放:

  • 图片已处理(通过您的代码,通常是using
  • 图像已完成(在垃圾回收期间/之后)

如果你有足够的内存,垃圾收集将不会经常运行,因此垃圾收集不会释放丢弃的句柄。这意味着你需要保持警惕,以便在完成后正确处理每个图像。

但是,诀窍在于知道何时“完成”图像。如果你处理了一个仍被UI使用的Image ......糟糕的事情。