将TBitmap转换为TPngImage并管理内存使用情况

3

我有一个由11个白色TBitmap组成的数组(32位512x512像素=1 MB),希望将它们分配给TPngImage数组以减少内存使用量。我希望这个1 MB的白色位图能够变成1.76 KB的png,并且内存使用量大幅降低。我用任务管理器监测了一下,发现差别只有0.824 MB,为什么会这样?在内存中无损压缩TBitmap的最佳/最快方法是什么?


for I := 0 to 10 do
begin
  Bitmaps[I] := TBitmap.Create;
  Bitmaps[I].PixelFormat := pf32bit;
  Bitmaps[I].Canvas.Pen.Color := clWhite;
  Bitmaps[I].SetSize(512,512);
  Bitmaps[I].Canvas.Rectangle(0,0,512,512);
end;

对于 I := 0 到 10 做如下操作:

创建 Pngs[I] 对象并将 Bitmaps[I] 赋值给它,然后释放 Bitmaps[I] 对象。


更新

根据 @bummi 的研究,我认为最好的做法是将 png 保存在内存流数组中,这会节省 9.7 MB 的空间。


for I := 0 to 10 do
begin
  Png :=  TPngImage.Create;
  Png.Assign(Bitmaps[I]);
  Streams[I] := TMemoryStream.Create;
  Png.SaveToStream(Streams[I]);
  Bitmaps[I].Free;
  Png.Free;
end;


3
你的循环展示了11个位图。 - OnTheFly
1
你尝试过最小化程序窗口吗?任务管理器的工作集与你当前使用的FastMM4堆不同。当你创建位图时,它可能会或可能不会向Windows请求更多的堆,但是当你释放它们时,应用程序并没有立即将其释放给Windows。如果这样做,应用程序将变得非常缓慢。请阅读有关堆、内存管理器和工作集的相关信息。 - Arioch 'The
1
哪个版本的Delphi?什么是TPngImage?你确定它实际上存储了压缩的位图吗?而且@Arioch'The是对的,使用任务管理器实际上无法以有意义的方式测量内存使用情况。你需要获得一个合适的工具。 - David Heffernan
3
阅读pngimage的资源时,数据在加载(分配)时被解压缩,并在保存时进行压缩。在内存中似乎没有压缩的数据。 - bummi
1
你可能会回答自己的问题... - bummi
显示剩余3条评论
2个回答

1
释放TBitmap时,您会释放两个东西:
  • 内存到FastMM4 Delphi堆管理器
  • HBITMAP Windows GDI句柄
有时,如果您最小化所有程序窗口,然后将它们恢复回来,Windows可能会缩小工作集,但这并不是保证的。由于今天10MB的相对较小差异而重新排列进程内存不会毫无意义地减慢速度。
阅读更多以 https://stackoverflow.com/a/14380287/976391 开始的答案。 http://fastmm.sourceforge.net/带有自述文件和演示如何测量进程内存使用情况,如果您感到好奇的话。
但是,如果您真的想要减少RAM使用率-那么就不要分配它。只需制作一个TBitmap并从中分配所有PNG即可。尽管再次提醒您,您的Widows明确表示,10MB不是需要关心的数字。

另外,正如用户539848所指出的那样,您有11个位图,而不是10个。为了避免偏移错误,最好不要使用神奇的常量,而是使用可靠的编译器结构。

for I := Low(Bitmaps) to High(Bitmaps) do
begin
  Bitmaps[I] :=...

0

TPngImage将所有像素保持在准备好的状态并解压以便能够快速绘制它们。TPngImage占用的内存大约与TBitmap相同。

因此,简单地将位图分配给TPngImage只会复制数据。因此,在释放位图后,您的程序最终将使用相同数量的内存。

如果您希望内存使用量降至1.76 KB png,则必须将PNG压缩到内存流中并释放TPngImage,就像您更新中的代码一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接