位图如何存储在 .NET 的内存中? [英] How are Bitmaps stored in memory in .NET?

查看:18
本文介绍了位图如何存储在 .NET 的内存中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 .NET 中,您通常使用 Bitmap 类来存储图像.要快速访问它,您需要调用 lock() 和unlock() 将位图的内容复制到内存中.那么,这是否意味着位图在锁定之前没有存储在打包的内存数组中?

In .NET you usually use the Bitmap class to store images. To access it quickly, you need to call lock() and unlock() to copy the contents of the bitmap into memory. So, does it mean that the bitmap was not stored in a packed memory array before locking?

究竟需要锁定什么?,即为什么平台不能简单地返回指向位图第一个像素的指针并让您直接访问像素?(除了不安全"的内存访问考虑)

Exactly what is the need for locking?, i.e. why couldn't the platform simply return a pointer to the first pixel of the bitmap and let you access the pixels directly? (apart from the "unsafe" memory access considerations)

一些可能的原因:

  • 位图以其原始压缩形式存储以节省内存(PNG、JPEG 等)
  • 位图以 24-bpp 格式存储,因此访问速度比 32-bpp 图像慢
  • 位图未存储在打包的内存阵列中并且是碎片化的,因此无法快速读取/写入
  • 位图以未公开的方式存储,平台不希望您访问实际位图数据内存 - 强制您使用 lock() 在内存中创建它的副本

推荐答案

位图以惰性方式读取.实际使用的算法在很大程度上取决于图像格式,.bmp 文件很容易,.jpeg 不是那么容易.在幕后,GDI+ 创建一个内存映射文件,以在必要时将文件数据映射到 RAM,利用操作系统的按需分页虚拟内存映射功能.正是这个 MMF 臭名昭著地在文件上创建了一个锁,并负责导致您在尝试将图像保存回同名文件时遇到的异常异常.

Bitmaps are read in a lazy fashion. The actual algorithm used depends a great deal on the image format, a .bmp file is easy, a .jpeg is not so easy. Under the hood, GDI+ creates a memory mapped file to map the file data into RAM, when necessary, taking advantage of the demand-paged virtual memory mapping feature of the operating system. It is this MMF that infamously creates a lock on the file and is responsible for the ratty exceptions you get when trying to save an image back to a file with the same name.

Bitmap.LockBits() 创建一个单独的缓冲区,将像素数据从 MMF 映射到内存中具有请求像素格式的区域.现在您拥有了独立于文件格式的明确定义格式的数据.调用 UnlockBits() 将修改后的数据写回(如果有).文件中的数据如何与修改后的像素重新组合的确切方式并未指定,并且可能在很大程度上取决于编解码器.

Bitmap.LockBits() creates a separate buffer that maps the pixel data from the MMF to an area in memory that has the requested pixel format. Now you have the data in a well defined format that's independent from the format in the file. Calling UnlockBits() writes the modified data back, if any. Exactly how the data from the file gets re-combined with the modified pixels is not specified and is likely to depend a great deal on the codec.

当你在其他方法中使用位图时,这种完全相同的锁定发生,看不见.就像您使用 Graphics.DrawImage() 绘制图像一样.当您使用 Bitmap.GetPixel() 时,臭名昭著.正如您现在可以猜到的,在锁定调用时转换像素数据涉及相当多的开销,原因是 GetPixel() 如此缓慢,因为您对位图中的每个像素都进行了操作,而不仅仅是一次,如DrawImage 和 LockBits() 可以.

This exact same locking happens, unseen, when you use the bitmap in other methods. Like when you draw the image with Graphics.DrawImage(). And infamously when you use Bitmap.GetPixel(). As you can guess by now, there's a fair amount of overhead involved in getting the pixel data converted at the lock call, the reason that GetPixel() is so slow since you do it for every pixel in the bitmap rather than just once, as DrawImage and LockBits() do.

还应该清楚的是,开销量在很大程度上取决于图像文件格式、动态解码像素数据的费用、解码器完成的缓存量、图像的像素格式文件与您在 LockBits() 中要求的像素格式.这里发生的事情太多,无法做出可预测的性能猜测,您必须对其进行分析.

It should be also clear that the amount of overhead depends a great deal on the image file format, the expense of decoding the pixel data on-the-fly, the amount of caching done by the decoder, the pixel format of the file versus the pixel format you ask for in LockBits(). There's way too much going on here to make predictable perf guesses, you'll have to profile it.

这篇关于位图如何存储在 .NET 的内存中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆