前几天维护的程序发生了内存不足的问题,经查看,是由于用户一次加载了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
|