C#分块数组

4

我需要分配非常大的简单结构体数组(1 GB RAM)。在几次分配/释放后,内存变得碎片化并抛出OutOfMemory异常。

这是在32位下。由于性能损失,我不想使用64位 - 相同的应用程序在64位模式下运行会慢30%。

您是否知道一些IList兼容数组的实现,它们按块分配内存而不是一次性分配?这将避免我的内存碎片问题。


奇怪,这其实是一个错误的问题。应该问“为什么我的64位程序要慢30%?”当你分块数组后,32位进程的速度也会变得非常慢。 - Hans Passant
最初该应用程序是64位的,但在阅读了一些文章后,发现64位JIT在优化代码方面不如32位(https://dev59.com/o3VD5IYBdhLWcg3wVKAb),因此我将其转换为32位,并发现这是真的。即使我在这里失去了速度,它仍然比64位版本启动更快 - 我正在使用IronPython + C#+ C++ / CLI,而64位版本启动需要多花10秒钟(由于IronPython)。 - Meh
3个回答

3

Josh Williams在他的博客上介绍了使用分块数组的BigArray<T>类:

BigArray<T>, 解决2GB数组大小限制

你可以在这个相关问题中找到更多有用的信息:

C#巨大的二维数组

一个简单的临时解决方案可能是为应用程序启用3GB开关。这样做可以使32位Windows的每个进程的2GB限制得以突破。但是,请注意,CLR允许的最大对象大小仍然是2GB。该开关可以通过主可执行文件的后置构建操作来启用:

call "$(DevEnvDir)..\tools\vsvars32.bat"
editbin.exe /LARGEADDRESSAWARE "$(TargetPath)"

我已经使用/LARGEADDRESSAWARE技巧并且它有很大帮助。 - Meh

1

在实例化数组时,.Net 会尝试找到一个连续的内存块来存储你的数组。由于32位应用程序的总内存限制为2Gb,因此在多次分配之后,要找到这样的内存块将变得困难。

  1. 您可以尝试使用类似于 LinkedList<T> 的东西,来避免需要进行连续分配,或者重构您的代码以使这些块更小(虽然这并不完全安全,即使是500Mb的数组也有可能无法满足需求)。

  2. 另一种解决方案是只在应用程序启动时实例化此大缓冲区一次,然后实现一种算法,在您的应用程序生命周期内重新使用相同的空间。

  3. 如果你可以使用 IEnumerable 而不是 IList 来传递数据给你程序中的其他部分,你就可以使用 SelectMany LINQ 方法来折叠这个列表。

  4. 最后,您可以在自定义类中实现 IList 接口,并在底层使用几个较小的数组。


0

3
将每个项目(8字节)存储在单独的节点中太浪费了。 - Meh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接