我目前正在开展一个医学图像处理项目,需要大量的内存.我可以做些什么来避免堆碎片并加快已经加载到内存中的图像数据的访问速度?
该应用程序是用C++编写的,可以在Windows XP上运行.
编辑:应用程序使用图像数据进行一些预处理,如重新格式化,计算查找表,提取感兴趣的子图像...应用程序在处理过程中需要大约2 GB RAM,其中大约可以使用1.5 GB对于图像数据.
如果您正在进行医学图像处理,则可能是您一次分配大块(512x512,每像素2字节图像).如果在图像缓冲区的分配之间分配较小的对象,碎片会咬你.
编写自定义分配器对于这个特定的用例来说并不一定困难.您可以为Image对象使用标准C++分配器,但对于像素缓冲区,您可以使用在Image对象中管理的自定义分配.这是一个快速而肮脏的轮廓:
使用结构的静态数组,每个结构具有:
一块可以容纳N个图像的固体内存 - 分块将有助于控制碎片 - 尝试初始N为5左右
并列的bool数组,指示相应的图像是否正在使用中
要分配,请在数组中搜索空缓冲区并设置其标志
如果找不到,请将新结构附加到数组的末尾
要解除分配,请在数组中找到相应的缓冲区并清除布尔标志
这只是一个简单的想法,有很多变化的空间.主要技巧是避免释放和重新分配图像像素缓冲区.
有答案,但如果不了解问题的细节就很难一般.
我假设是32位Windows XP.
尽量避免需要100 MB的连续内存,如果你运气不好,一些随机的dll会通过可用的地址空间在不方便的点上加载自己,迅速减少非常大的连续内存区域.根据您需要的API,这可能很难预防.令人惊讶的是,除了一些"正常"的内存使用情况之外,分配几个400MB的内存块会让你无处可分配一个最终的'小'40MB块.
另一方面,请一次预先分配合理大小的块.10MB左右的顺序是一个很好的折衷块大小.如果您可以设法将数据划分为这种大小的块,则可以合理有效地填充地址空间.
如果您仍然要用完地址空间,那么您将需要能够根据某种缓存算法进出页面块.选择合适的块来分页将非常依赖于您的处理算法,需要仔细分析.
选择在哪里分页是另一个决定.您可能决定只将它们写入临时文件.您还可以调查Microsoft的Address Windowing Extenstions API.在任何一种情况下,您都需要在应用程序设计中小心清理任何指向即将被分页的指针,否则会发生非常糟糕的事情(tm).
祝好运!
如果您要对大图像矩阵执行操作,您可能需要考虑一种称为"平铺"的技术.通常的想法是将图像加载到存储器中,使得相同的连续字节块不包含一行中的像素,而是包含2D空间中的正方形.这背后的基本原理是,您将在2D而不是在一条扫描线上执行更多彼此更接近的操作.
这不会减少您的内存使用,但可能会对页面交换和性能产生巨大影响.