我有点困惑。在操作系统课程中,我们被告知所有操作系统都通过分页或分段来处理内存碎片化,并且根本没有连续的物理内存分配。操作系统使用不同级别的寻址(逻辑/物理)来避免连续的内存分配。现在这里有很多讨论。我的问题是: 对于支持逻辑寻址的操作系统,在C++编程中是否真的存在这个问题(是否会因为内存碎片而导致任何进程崩溃)?如果是,为什么首先每个操作系统都试图避免连续寻址?
我有点困惑。在操作系统课程中,我们被告知所有操作系统都通过分页或分段来处理内存碎片化,并且根本没有连续的物理内存分配。操作系统使用不同级别的寻址(逻辑/物理)来避免连续的内存分配。现在这里有很多讨论。我的问题是: 对于支持逻辑寻址的操作系统,在C++编程中是否真的存在这个问题(是否会因为内存碎片而导致任何进程崩溃)?如果是,为什么首先每个操作系统都试图避免连续寻址?
内存分配器通常无法释放大块内存,如果其中至少有一些被分配。这里有一个部分解决方案,利用虚拟内存组织中的页面 - 所谓的“惰性释放”机制,由Linux和BSD上的MADV_FREE
以及Windows上的DiscardVirtualMemory
表示。当您有一个巨大的内存块只被部分使用时,您可以通知内核该内存的一部分不再需要,并且在内存压力下可以将其收回。这是惰性完成的,仅在内存压力下才执行,因为内存释放非常昂贵。但是,出于性能原因,许多内存分配器仍然不使用它。
因此,对于您的问题的答案 - 这取决于您关心程序的效率程度。大多数程序不关心,因为标准分配器只需完成任务。当标准分配器无法高效地完成其工作时,一些程序可能会受到影响。
操作系统并没有避免连续内存分配。在顶层,有硬件和软件。硬件资源有限,这里指物理内存。为了共享资源并避免用户程序处理其共享,虚拟地址层应运而生。它只是将连续的虚拟寻址空间映射到稀疏的物理区域。换句话说,0x10000虚拟地址可以在一个进程中指向0x80000物理地址,在另一个进程中则可以指向0xf0000。
分页和交换意味着将一些页面或整个应用程序内存写入磁盘,然后在某个时间点将其带回。它很可能在之后具有不同的物理页面映射。
因此,您的程序始终会看到连续的虚拟寻址空间,但在物理硬件空间中真正是碎片化的。顺便说一下,这是通过常量块大小完成的,并且没有浪费或未使用的内存空洞。
现在,第二级碎片化是由new
/malloc
函数引起的,与您分配和删除不同大小的内存有关。这会在虚拟空间中分割您的堆。这些函数确保尽可能少的浪费。
因此,在通用的C++(或任何其他语言)编程中,您不需要关心任何内存碎片化。您分配的所有块都保证在虚拟空间中是连续的(不一定在物理上)。