9

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

4

2 回答 2

7

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

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

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

如果操作系统是指“内核”,那么它无法帮助您处理进程地址空间中发生的碎片(堆碎片)。C 库应该尽量避免碎片化,不幸的是,它并不总是能够这样做。请参阅链接的问题

如果其中至少分配了一些东西,内存分配器通常无法释放大块内存。MADV_FREE对此有一个部分解决方案,它利用页面中的虚拟内存组织 -在 Linux 和 BSD 以及DiscardVirtualMemoryWindows上以所谓的“惰性”机制为代表。当你有一大块只被部分使用的内存时,你可以通知内核这部分内存不再需要并且它可以在内存压力下收回它。这是懒惰的,并且只在内存压力下完成,因为内存释放非常昂贵。但是出于性能原因,许多内存分配器仍然不使用它。

所以你的问题的答案——这取决于你对程序效率的关心程度。大多数程序并不关心,因为标准分配器只是为他们完成工作。当标准分配器无法有效地完成其工作时,某些程序可能会受到影响。

于 2018-08-25T14:32:30.100 回答
3

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

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

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

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

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

于 2018-08-25T14:39:41.373 回答