我有点困惑。在操作系统课程中,我们被告知所有操作系统都通过分页或分段来处理内存碎片,并且根本没有连续的物理内存分配。操作系统使用不同级别的寻址(逻辑/物理(来避免连续的内存分配。现在这里有很多关于它的讨论。我的问题是: 在支持逻辑寻址的操作系统的 C++ 编程中,这个问题是否真实存在(任何进程是否仅仅因为内存碎片而崩溃(? 如果是,为什么每个操作系统首先都试图避免连续寻址?
有 2 层:虚拟进程地址空间中的碎片和物理内存中的碎片。
如果您查看任何现代应用程序,您可以看到由于内存未释放到操作系统,其内存使用量如何随着时间的推移而增长。您可以说这是由其他原因引起的,但内存碎片(例如分配的内存块的非连续位置(是造成这种情况的核心原因。简而言之,内存分配器拒绝向操作系统释放内存。
如果您对物理内存中的碎片感兴趣,那么即使内存组织在页面中,仍然需要分配物理上连续的内存块。例如,如果您需要避免虚拟内存开销,则可能需要使用大页面(Linux中的"大页面"(。x86_64支持 4KiB、2MiB 和 1GiB 页面。如果没有所需大小的连续物理内存,您将无法使用它们。
如果您所说的操作系统是指"内核",那么它无法帮助您解决进程地址空间中发生的碎片(堆碎片(。C 库应该尽量避免碎片,不幸的是,它并不总是能够这样做。请参阅链接的问题。
如果内存分配器中至少分配了某些内容,则通常无法释放大块内存。对此有一个部分解决方案,它利用页面中的虚拟内存组织 - 所谓的"无惰"机制,以Linux和BSD上的MADV_FREE
和Windows上的DiscardVirtualMemory
表示。当您有一大块内存仅部分使用时,您可以通知内核不再需要该内存的一部分,并且可以在内存压力下将其收回。这是在内存压力下延迟完成的,并且仅在内存压力下完成,因为内存释放非常昂贵。但是出于性能原因,许多内存分配器仍然不使用它。
所以你的问题的答案 - 这取决于你对程序效率的关心程度。大多数程序并不关心,因为标准分配器只是为他们完成工作。当标准分配器无法有效地完成其工作时,某些程序可能会受到影响。
操作系统不会避免连续的内存分配。在顶层,您拥有硬件和软件。硬件资源有限,在这种情况下是物理内存。为了共享资源并避免用户程序处理其共享,发明了虚拟寻址层。它只是将连续的虚拟寻址空间映射到稀疏的物理区域。换句话说0x10000虚拟地址可以在一个进程中指向0x80000物理地址,而在另一个进程中指向0xf0000。
分页和交换意味着将某些页面或整个应用程序内存写入磁盘,然后在某个时候将其恢复。它之后很可能有不同的物理页面映射。
因此,您的程序将始终看到连续的虚拟寻址空间,这在物理硬件空间中实际上是碎片化的。顺便说一句,它是以恒定的块大小完成的,并且没有浪费或未使用的内存孔。
现在,由new
/malloc
函数引起的第二级碎片与您分配和删除不同大小的内存有关。这会在虚拟空间中对堆进行分段。这些功能确保尽可能少的浪费。
因此,在您的通用C++(或任何其他语言(编程中,您不关心任何内存碎片。您分配的所有块都保证在虚拟空间中是连续的(不一定在物理空间中(。