我使用MFC和OpenGL在C ++中创建了一个简单的2D图像查看器。该图像查看器允许用户打开图像,放大/缩小,平移,以及以不同颜色层(青色,黄色,品红色,黑色)查看图像。该程序非常适合合理大小的图像。但是我正在对一些非常大的图像进行压力测试,而且我很容易耗尽内存。我有一个这样的图像是16,700x15,700。我的程序甚至可以在绘制任何内容之前耗尽内存,因为我正在动态创建大小为UCHAR[]
的{{1}}。我将它乘以4,因为当我将此数组提供给height x width x 4
时,每个RGBA值都有一个字节
我做了一些搜索并阅读了一些关于将图像分割成图块的信息,而不是单个图像上的一个大纹理。这是我应该做的事吗?这对我的记忆有什么帮助?或者我应该做些什么更好的事情?
答案 0 :(得分:0)
您的分配大小为16.7k * 15.7k * 4,大小约为1GB。其余的答案取决于您是编译为32位还是64位可执行文件以及您是否正在使用物理地址扩展(PAE)。如果你不熟悉PAE,顺便说一句,你很可能没有使用它。
假设32位
如果你有32位可执行文件,你可以处理3GB的内存,这样你的三分之一内存就会在一次分配中耗尽。现在,为了解决这个问题,当你分配一块内存时,那个内存必须作为一个连续的可用内存范围。您可以轻松获得超过1GB的内存,但是大小小于1GB,这就是为什么人们建议您将纹理分成多块。将其拆分为32 x 32个较小的磁贴意味着您要分配1024个1MB的分配(这可能是不必要的细粒度)。 注意:引用需要但是某些linux模式只允许2GB ..
假设64位
你似乎不太可能构建一个64位可执行文件,但如果你那么逻辑上可寻址的内存要高得多。典型数字为2 ^ 42或2 ^ 48(分别为4096 GB和256 TB)。这意味着大量分配不应该在人工压力测试之外的任何其他情况下失败,并且在耗尽逻辑内存之前你将终止你的交换文件。
如果您的约束/硬件允许,我建议建立64位而不是32位。否则,请参阅以下
平铺与子采样
平铺和子采样不是预先相互排斥的。您可能只需要进行一次更改即可解决问题,但您可能会选择实施更复杂的解决方案。
如果您处于32位地址空间,则平铺是个好主意。它使代码复杂化,但删除了您似乎面临的单个1GB连续块问题。如果你必须构建一个32位可执行文件,我宁愿通过对图像进行二次采样。
对图像进行二次采样意味着对于二次采样与原始图像,您有一个额外的(虽然更小)内存块。它可能在openGL中具有性能优势,但可以将其设置为额外的内存压力。
第三种方法,其他复杂情况是在必要时从磁盘流式传输图像。如果缩小以显示整个图像,则将在1920 x 1200显示器上对每个屏幕像素进行二次采样> 100像素。您可以选择创建默认情况下显着二次采样的图像,并使用该图像直到您进行了充分放大,以至于需要更高分辨率版本的 子集 图片。如果您使用SSD,这可以提供可接受的性能,但通过额外的复杂性增加了很多。