firemail

标题: Image对象的内存占用问题。 [打印本页]

作者: Qter    时间: 2022-11-25 13:58
标题: Image对象的内存占用问题。

前几天维护的程序发生了内存不足的问题,经查看,是由于用户一次加载了15张图片,每张图片的大小都接近1M,用户把图片修改后,程序可以正常处理了。

不过又想了一下,15张JPG图片的大小 加起来也不过是最大15M而已,也不至于内存不够呀!

于是检查代码:


debug时发现只要执完 orginalimg = (Bitmap)Image.FromStream(picStream);  这一句,内存暴增100多M。然后图片的大小只有700多K,开始时,以为是Memorystream没有释放资源,弄了很久,也没有解决问题。

最后看到网上有人遇到类似的问题,有人提醒说有可能是Image的问题。

然后加上了orginalimg.Dispose()这句,发现果然,只要这一句一执行,点用的100多M内存就释放了。

可是由于后面还需要用到这个image,这时不能释放。因为界面会显示加载的所有图片的小图。

然后决定重点查了一下: 为什么一个700多K的JPG读到一个IMG对象后,会变成上白兆?


经过一翻Google后,发现在IMage的内存占用大小的计算方法如下:

Image在内存中占用的空间计算:

如果是32位,确实是Width   *   Height   *   4   
  实际上应该是Height   *(((Width   *   32)   +   31)   /   32)   *   4   
   
  如果是24位的化,就不一定是Width   *   Height   *   3了,   
  而是Height   *(((Width   *   24)   +   31)   /   32)   *   4   


Note: 上面的Height 和Weight是图片的原始大小。可以根据Image的这两个属性值来查看具体的大小。



查看了一下我读入的图片的大小是:Height= 6800, Width = 4400. 代入上面的公式一算,果然是100M多(另上面公式算出来的是字节数,除以1024*1024可以得到多少M)


PS:所以我读的图片是JPG格式, jpg是压缩格式的位图,它本身不是真正的原始位图,进入内存后,要经过一定的算法的才能成为原始位图,也就是说,内存中的才是真正原始位图的大小,这时,它是未压缩的,并以纯二进制表示的,所以占用内存超出文件的大小。


由于界面显示的是缩略图,所以我只需要把图片尺寸改小,就应该能正常显示了,

double scale = 0.1

originalIMG = orginalimg.GetThumbnailImage(Convert.ToInt32(orginalimg.Size.Width * scale), Convert.ToInt32(orginalimg.Size.Height * scale), null, IntPtr.Zero)


完成后再调用orginalimg.Dispose()释放那100M多内存。这样,当用户读一系列的图片进来时,就可以正常显示了。




(另:如果需要单独看某一张图片用原始尺寸,可以用一个变量把图片按字节读进来,然后单独显示时,再读到IMG,这样程序也可以正常显示,因为也就是100多M,而不是多个100M)。






本文链接:https://www.ngui.cc/el/1232862.html





欢迎光临 firemail (http://firemail.wang:8088/) Powered by Discuz! X3