“内存碎片”仍然是个问题吗?

时间:2018-08-25 14:13:21

标签: c++ memory-management memory-fragmentation

我有点困惑。在操作系统课程中,我们被告知所有操作系统都通过分页或分段来处理内存碎片,并且根本没有连续的物理内存分配。 OS使用不同级别的寻址(逻辑/物理)来避免连续的内存分配。现在here对此有很多讨论。我的问题是: 这个问题在支持逻辑寻址的OS的C ++编程中是否存在(是否仅由于内存碎片而导致任何进程崩溃)?如果是,为什么每个操作系统都首先尝试避免连续寻址?

2 个答案:

答案 0 :(得分:6)

共有2层:虚拟进程地址空间中的碎片和物理内存中的碎片。

如果您查看任何现代应用程序,您会看到它的内存使用率随着时间的推移如何增长,因为内存没有释放到操作系统。您可以说这是由其他原因引起的,但是内存碎片(例如分配的内存块的不连续位置)是造成此问题的主要原因。简而言之,内存分配器拒绝将内存释放给操作系统。

如果您对物理内存中的碎片感兴趣,那么即使将内存组织在页面中,仍然需要分配物理上连续的内存块。例如,如果您需要避免虚拟内存开销,则可能要使用大页面(在Linux中为“大页面”)。 x86_64支持4KiB,2MiB和1GiB页面。如果没有所需大小的连续物理内存,则将无法使用它们。

如果在操作系统中您的意思是“内核”,则它不能帮助您解决进程地址空间中发生的碎片(堆碎片)。 C库应尽量避免碎片化,不幸的是,它并非总是能够这样做。请参阅链接的question

如果内存分配器中至少分配了某些内容,则通常无法释放大块内存。有一种解决方案,可以利用页面中的虚拟内存组织功能-所谓的“无延迟”机制,在Linux和BSD上由MADV_FREE表示,在Windows上由DiscardVirtualMemory表示。当您拥有仅部分使用的巨大内存块时,可以通知内核不再需要该部分内存,并且可以在内存压力下将其收回。这是懒惰的,并且仅在内存压力下完成,因为内存重新分配非常昂贵。但是出于性能原因,许多内存分配器仍然不使用它。

因此,问题的答案-取决于您对程序效率的关心程度。大多数程序都不在乎,因为标准分配器只是为它们完成工作。当标准分配器无法有效完成其工作时,某些程序可能会受到影响。

答案 1 :(得分:3)

OS不能避免连续内存分配。在顶层,您具有硬件和软件。硬件资源有限,在这种情况下为物理内存。为了共享资源并避免用户程序进行共享,发明了虚拟寻址层。它只是将连续的虚拟寻址空间映射到稀疏的物理区域。换句话说,0x10000虚拟地址可以在一个进程中指向0x80000物理地址,而在另一个进程中可以指向0xf0000。

分页和交换意味着将某些页面或整个应用程序内存写入磁盘,然后将其恢复。它很可能在其后具有不同的物理页面映射。

因此,您的程序将始终看到连续的虚拟寻址空间,该空间实际上分散在物理硬件空间中。顺便说一句,这是通过恒定的块大小完成的,并且没有浪费或未使用的内存孔。

现在,第二个碎片级别是由new / malloc函数引起的,它与您分配和删除不同大小的内存有关。这会将您的堆分散在虚拟空间中。这些功能确保尽可能减少浪费。

因此,在您的通用C ++(或任何其他语言)编程中,您无需担心任何内存碎片。您分配的所有块都保证在虚拟空间中是连续的(不一定在物理空间中)。