我需要分配非常大的简单结构体数组(1 GB RAM)。在几次分配/释放后,内存变得碎片化并抛出OutOfMemory异常。
这是在32位下。由于性能损失,我不想使用64位 - 相同的应用程序在64位模式下运行会慢30%。
您是否知道一些IList兼容数组的实现,它们按块分配内存而不是一次性分配?这将避免我的内存碎片问题。
我需要分配非常大的简单结构体数组(1 GB RAM)。在几次分配/释放后,内存变得碎片化并抛出OutOfMemory异常。
这是在32位下。由于性能损失,我不想使用64位 - 相同的应用程序在64位模式下运行会慢30%。
您是否知道一些IList兼容数组的实现,它们按块分配内存而不是一次性分配?这将避免我的内存碎片问题。
Josh Williams在他的博客上介绍了使用分块数组的BigArray<T>
类:
你可以在这个相关问题中找到更多有用的信息:
一个简单的临时解决方案可能是为应用程序启用3GB开关。这样做可以使32位Windows的每个进程的2GB限制得以突破。但是,请注意,CLR允许的最大对象大小仍然是2GB。该开关可以通过主可执行文件的后置构建操作来启用:
call "$(DevEnvDir)..\tools\vsvars32.bat"
editbin.exe /LARGEADDRESSAWARE "$(TargetPath)"
在实例化数组时,.Net 会尝试找到一个连续的内存块来存储你的数组。由于32位应用程序的总内存限制为2Gb,因此在多次分配之后,要找到这样的内存块将变得困难。
您可以尝试使用类似于 LinkedList<T>
的东西,来避免需要进行连续分配,或者重构您的代码以使这些块更小(虽然这并不完全安全,即使是500Mb的数组也有可能无法满足需求)。
另一种解决方案是只在应用程序启动时实例化此大缓冲区一次,然后实现一种算法,在您的应用程序生命周期内重新使用相同的空间。
如果你可以使用 IEnumerable 而不是 IList 来传递数据给你程序中的其他部分,你就可以使用 SelectMany
LINQ 方法来折叠这个列表。
最后,您可以在自定义类中实现 IList 接口,并在底层使用几个较小的数组。