我有一个包含图像的类:
class AnyClass
{
Image AnyImage;
string AnyString;
}
当我创建超过2000个此类的实例时,我有一个OutOfMemoryException
要分配给AnyClass
的图片只有3个图标大小
这些实例将作为ListView的数据源。
有没有办法在AnyClass
中通过引用分配图像?
或者处理这种情况的方式/模式是什么?
:
尚未测试代码,但这与正在进行的操作类似:
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;
}
答案 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
......糟糕的事情。