我目前正在为医学图像处理的一个项目,是需要大量的内存。 有什么我可以做,以避免堆碎片,并加快已经被加载到内存中的图像数据的访问?
这个应用程序已经用C ++编写,并运行于Windows XP。
编辑:该应用程序一些预处理与图像数据,重新格式化等,计算的查找表,提取感兴趣子图像...应用程序需要处理期间约2 GB RAM,其中可以使用约1.5 GB为图像数据。
我目前正在为医学图像处理的一个项目,是需要大量的内存。 有什么我可以做,以避免堆碎片,并加快已经被加载到内存中的图像数据的访问?
这个应用程序已经用C ++编写,并运行于Windows XP。
编辑:该应用程序一些预处理与图像数据,重新格式化等,计算的查找表,提取感兴趣子图像...应用程序需要处理期间约2 GB RAM,其中可以使用约1.5 GB为图像数据。
如果你正在做医学图像处理,很可能你是在一次分配大的块(512×512,每个像素的图片2字节)。 如果分配图像缓冲区分配之间更小的物体碎片会咬你。
编写自定义分配器不一定难这个特定用例。 您可以使用标准的C ++分配器为您的图片对象,但像素缓冲区可以使用自定义的分配是所有的图片对象中进行管理。 这里有一个快速和肮脏的轮廓:
这与大量的空间,变化只是一个简单的想法。 主要的窍门是避免释放和重新分配所述图像像素缓冲器。
有答案,但它是很难被一般不知道这个问题的细节。
我假设的32位Windows XP。
尽量避免需要连续内存的MB的100年代,如果你运气不好,一些随机的DLL将在inconventient点通过你提供的地址空间迅速削减的连续内存的非常大的区域加载自己。 根据你所需要的的API,这可能是非常难防。 它可以是相当令人惊讶的只是分配了几个,除了一些“正常”内存使用400MB的内存块可以让你无处可分配最终的“小” 40MB块。
在另一方面,做预分配合理大小的块在同一时间。 10MB左右的订单是一个很好的妥协块大小。 如果你可以管理你的数据划分为这种大小的块,你就可以合理有效地填充的地址空间。
如果你还是会用完的地址空间,你将需要在能够页面区块和出基于某种缓存算法的。 选择合适的块换出将要在很大程度上取决于你的处理algortihm,需要仔细分析。
其中,选择页面的东西出来是另一个决定。 您可能决定只是其中写入临时文件。 您也可以调查微软的地址窗口Extenstions API。 在这两种情况下,你需要在你的应用程序设计,以清理指向的东西,即将被换出,否则真的不好的事情(TM)会发生任何指针小心。
祝好运!
如果你要在一个大的图像矩阵可以执行操作,你可能要考虑一个名为“拼接”技术。 这个想法通常是加载在图像中存储器,这样的字节相同的连续块中不含有在一个行的像素,而是在二维空间中的正方形。 这样做的理由是,你会做更多的操作更接近二维对方,而不是一个扫描线。
这不会减少你的内存使用,但可能对页面交换和性能产生巨大的影响。
没有关于这个问题(例如语言)更多的信息,有一两件事你可以做的是通过重用分配,以避免分配流失,不分配,运营和自由。 分配器如dlmalloc处理破碎比Win32的堆好。
你将在这里打的虚拟地址范围的限制,这与32B的Windows为您提供了最多2 GB。 你应该也知道,使用像的DirectX或OpenGL图形API将使用这些2 GB的广泛部分,用于帧缓冲器,纹理及类似数据。
1.5-2 GB为32B的应用是非常难以实现的。 最优雅的方式来做到这一点是使用64B OS和64b应用。 即使64B OS和32b应用,这可能在一定程度上可行,只要您使用LARGE_ADDRESS_AWARE
。
然而,当你需要存储的图像数据,你也可以通过使用来解决这个文件映射为内存存储 -这可以在你有一个记忆致力于和方便的方式来完成,但不使用任何虚拟在所有地址。
猜在这里,你的意思是避免碎片并不能避免碎片整理 。 还猜测,你是一个非托管语言(C或C ++可能)工作。 我建议你分配大块内存,然后成为从分配的内存块堆分配。 此内存池,因为含有大块内存是lessely容易碎裂。 综上所述,你应该实现一个自定义的内存分配器。
看到一些总体思路这里 。
我客串你使用非托管的东西,因为在管理平台系统(垃圾收集器)需要破碎的照顾。
对于C / C ++,你可以使用一些其他的分配器,比默认的一个。 (有alrady关于stackowerflow分配器一些线程)。
此外,您还可以创建自己的数据存储。 例如,在我目前从事的项目,我们有位图自定义存储(池)(我们将其存储在一个大的内存contigous大块),因为我们有很多人,我们跟踪堆的当碎片是大碎片和碎片整理。
您可能需要实施手动内存管理。 在图像数据长寿? 如果没有,那么你可以使用Apache Web服务器所用的模式:分配大量内存并把它们包装成内存池。 通过这些池在功能的最后一个参数,这样他们就可以使用游泳池,以满足需要分配临时存储器。 一旦调用链完成后,池中所有的内存可以应不再使用,所以你可以擦洗内存区域,并再次使用它。 分配的速度快,因为它们只意味着增加值的指针。 释放是非常快的,因为你会释放的内存非常大的块一次。
如果您的应用程序是多线程的,你可能需要将池存储在线程本地存储,以避免跨线程的通信开销。
如果你能准确地隔离那些你很可能会分配大块地方,你可以(在Windows上)直接调用的VirtualAlloc而不是通过内存管理器去。 这将避免正常的内存管理器中的碎片。
这是一个简单的解决方案,它不需要你使用自定义的内存管理器。