NSK*_*pro 2 c# memory garbage-collection heap-memory
我想了解 C# 中堆的完整使用。我了解堆栈和堆的工作原理,但我没有找到堆碎片整理的任何解释(如果可能的话)。
我读了很多关于 GC 在堆上分配和释放内存块时碎片问题的文章。
因此,如果有人可以向我解释或提供一些关于这个问题和堆(内存)碎片整理的好文章。
如果您了解堆的工作原理,我假设您知道有几种不同类型的堆。请参阅我的答案 - Stack vs. Heap in .NET
因此,我在该答案中提到的两个堆是大型对象堆 (LOH) 和 GC 堆(也称为临时堆)。
对于.NET来说一般不需要担心堆碎片。.NET 的 GC 工作分为 3 个步骤:标记、清除、压缩。标记 - 扫描所有有根引用并列出有根引用的列表- 这些不符合垃圾回收条件,也不会被触及。扫描 - 清除列表中未列出的项目的内存,并清除已标记项目的“标记位”。紧凑 - 移动剩余根对象的内存,使其位于连续的块中。压缩阶段的一个警告是,至少从最新版本的 .NET 4.6.2 开始,LOH 并未被压缩。这是 CLR GC 团队做出的设计决策,因为性能原因以及将所有内存移动到连续块所需的时间。自 .NET 1.0 以来,性能有了很多很多改进,因此 GC 不再像以前那样糟糕。无论如何,Gen 0、1 和 2 的堆都会被压缩。因此,无需担心那里的碎片。在大多数情况下,LOH 不会因其实现的算法而出现碎片问题。在某些情况下,LOH 可能会出现碎片。这可能是由多种原因引起的 - 其中一些是错误的分配模式、频繁的 Full GC 收集等。这可以通过改进分配模式、尽可能紧密地分配大块内存(以编程方式)以及对象池来解决。
从 .NET 4.5.1 开始,有一种方法可以手动压缩 LOH,但我强烈建议不要使用它,因为它会对您的应用程序造成巨大的性能影响,原因有两个:
有关 GC 标记、扫描、紧凑的信息 - https://blogs.msdn.microsoft.com/abhinaba/2009/01/30/back-to-basics-mark-and-sweep-garbage-collection/
有关 LOH 分配算法的信息: https://www.red-gate.com/simple-talk/dotnet/net-framework/the-dangers-of-the-large-object-heap/