Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.NET图像类的内存使用和碎片:位图与图元文件_.net_Image_Memory - Fatal编程技术网

.NET图像类的内存使用和碎片:位图与图元文件

.NET图像类的内存使用和碎片:位图与图元文件,.net,image,memory,.net,Image,Memory,由于内存不足异常似乎过早出现,我们一直在仔细检查各种.NET结构的内存使用情况。。。特别是那些倾向于分割大对象堆的大对象,导致过早出现内存不足异常。一个有点令人惊讶的领域是.NET图像类:位图和图元文件 以下是我们认为我们已经了解到的内容,但无法找到MS文档进行验证,因此我们希望其他人能够给予确认: (1) 从压缩光栅文件(JPG、PNG、GIF等)创建位图对象时,它会以该文件的完全分辨率为完全未压缩的像素阵列消耗内存。因此,例如,一个9000x3000像素的5MB JPG将扩展为9000x30

由于内存不足异常似乎过早出现,我们一直在仔细检查各种.NET结构的内存使用情况。。。特别是那些倾向于分割大对象堆的大对象,导致过早出现内存不足异常。一个有点令人惊讶的领域是.NET图像类:位图和图元文件

以下是我们认为我们已经了解到的内容,但无法找到MS文档进行验证,因此我们希望其他人能够给予确认:

(1) 从压缩光栅文件(JPG、PNG、GIF等)创建位图对象时,它会以该文件的完全分辨率为完全未压缩的像素阵列消耗内存。因此,例如,一个9000x3000像素的5MB JPG将扩展为9000x300x3字节(假设为24位颜色,无alpha),或消耗81MB内存。对吗

(1a)有证据(见下文2b)表明它还存储原始压缩格式。。。所以,在这种情况下,实际上是86MB。但这还不清楚。。。有人知道吗

(2) 创建图元文件对象,然后在其中绘制光栅文件(JPG、PNG、GIF等)时,只会消耗压缩文件的内存。因此,如果将9000x3000像素的5MB JPG绘制到元文件中,它只会消耗大约5MB的内存。对吗

(2a)要将光栅文件绘制到图元文件对象中,唯一的方法似乎是加载带有该文件的位图,然后将位图绘制到图元文件中。有没有更好的方法不需要临时加载巨大的位图数据(并导致相关的内存碎片)

(2b)将位图绘制到图元文件时,它使用与原始压缩文件大小相似的压缩格式。它是通过将原始压缩文件存储在位图中来实现的吗?还是使用原始压缩设置重新压缩扩展的位图

(3) 我们最初假设大型(>85KB)图像对象将被放置在大型对象堆中。事实上,情况似乎并非如此。相反,每个位图和每个图元文件都是小对象堆中的一个24字节对象,该小对象堆引用包含真实数据的本机内存块。对吗

(3a)我们假设这种本机内存就像大型对象堆一样,无法压缩。。。一旦将大对象放入本机内存中,它将永远不会被移动,因此本机内存的碎片化可能会导致与大对象堆碎片化一样多的问题。是吗?或者是否有更有效的底层位图/图元文件数据的特殊处理

(3b)因此,似乎有四个单独管理的独立内存块,每个内存块的内存不足都会导致相同的内存不足异常:小对象堆(托管对象<85KB,由GC压缩)、大对象堆(托管对象>85KB,由GC收集,但未压缩)、本机内存(非托管对象,可能未压缩)和桌面堆(管理windows句柄和如此有限的资源的地方)。我是否正确记录了这四个方面?还有其他方面我们应该注意吗

如果有一本好书或一篇文章能充分解释上述内容,请让我知道。(我很乐意阅读要求的内容;但绝大多数书都没有那么深入,因此不要告诉我任何我不知道的事情。)


谢谢!

我知道其中一些问题的答案:

(1) 是的,这是位图图像的定义

(3) 是的,这就是位图实现IDisposable接口的原因

(3a)这似乎令人惊讶。处理完位图对象后,是否正在对其运行Dispose()方法


(3b)至少有这四种,是的。

有两种存储图像数据的方法:作为像素,或作为向量。
位图
是关于像素,
图元文件
是关于像素和向量。向量数据的存储效率更高

要允许对位图进行操作,其数据必须以未压缩的方式存储在内存中。否则,
GetPixel
SetPixel
必须对位图进行解压缩、更改,每次更改都要重新压缩位图(如果可以开始的话)

是由Microsoft创建的,旨在与GDI一起使用,因此它可能包含一些直接与图形卡一起使用的内存效率更高的压缩算法。此外,元文件没有
GetPixel
SetPixel
方法,因此不必在内存中解压缩即可进行操作


您不必关心运行时使用的内存池。还有很多,由运行时决定将对象放置在何处。此外,您不必关心使用(大型)对象可能导致的内存不足异常。运行时将尽其所能(将对象放在其他对象之间的间隙中,压缩堆,扩展可用虚拟内存),以确保不会出现内存不足异常。如果确实出现了这种异常,则代码中可能还有另一个问题需要解决(例如内存泄漏)

内存堆、映射和表的概述:()



此外,您认为超过85 KiB的对象放在大型对象堆上的假设并不完全正确。对于当前版本的CLR中的大多数对象来说,这是正确的,但例如8 KiB的双精度数组(1000双精度数组)也在大型对象堆上分配。让运行时自己来考虑这个问题。

GDI+将图像数据存储在非托管内存中。因此,您的假设都不可靠。忘记处理位图是一种快速达到OOM的方法。地址空间碎片是另一种方法,32位进程在一段时间后会达到90 MB,成为危险区域。“你的假设都不靠谱”?但是