探讨C++中多次进行`new`操作而产生的非连续地址现象,需要考虑操作系统的内存管理机制、内存分配器的策略、以及C++运行时环境的特殊处理。核心观点包括:1、内存分配与回收、2、内存对齐、3、内存碎片及合并。在C++程序执行期间,内存连续性不保证主要受控于操作系统如何在进程的虚拟地址空间分配内存页。操作系统为了优化性能,防止碎片化,可能会分配非连续的物理内存。
一、内存分配与回收
内存分配(Memory Allocation)涉及操作系统为应用程序提供空闲内存的过程。当通过`new`操作请求内存时,编译器会调用内存分配器向系统申请必要的空间。见过回收,操作系统可将不再使用的内存归还至可用资源池,待后续分配。
二、内存对齐
内存对齐(Memory Alignment)是计算机系统中约定的、为了访问内存时提升性能的手段。依据数据类型大小,内存分配器可能会在地址上做一定的对齐,以确保数据结构按照其自然边界存储,提升访存效率。
三、内存碎片及合并
内存碎片(Memory Fragmentation)是内存使用不当导致的空间闲置现象。它包括外部碎片与内部碎片,其中外部碎片可通过合并邻近的空闲区域部分解决。而内存分配器可能根据历史分配模式,回收时将多个小空闲块合并为大块,以优化未来的分配请求。
四、操作系统内存管理机制
在解释不同`new`操作为何产生非连续内存地址前,需先理解操作系统的内存管理机制。操作系统管理内存的方式对程序申请和释放内存块的位置有显著影响。操作系统通过虚拟内存管理每个进程,意味着进程操作的地址并非直接对应物理内存地址。虚拟内存技术 允许非连续的物理内存片段映射到连续的虚拟地址空间,以此隐藏物理内存的复杂性。因此,即使连续分配内存,操作系统也可能由于旨在优化的内存管理策略,如页面换入换出、防止碎片化等,分配位于不同物理内存页的地址。
五、内存分配器的工作原理
C++通过`new`和`delete`关键词进行动态内存分配与释放。这些关键词背后,运行库通常会调用低级的内存分配函数如malloc/free。内存分配器通常会有一套自己的算法来管理内存,比如空闲链表、分区等。这些算法未必总是返回连续的内存块,特别是当有请求特定大小的内存时。内存分配器会尽量找到最匹配的内存块来避免浪费,这可能意味着分配相邻但非连续的地址。内存分配的效率 和应对碎片化问题也是分配器考虑的问题,而这些可能进一步导致非连续的内存分配。
六、内存对齐的必要性
计算机系统在硬件层面上有数据对齐的要求。对齐指的是数据存储的起始地址能够被其大小或某一固定数整除。这可以加快CPU的数据访问速度。例如,一个4字节的int型数据的起始地址最好是4的倍数。因此,内存分配器在分配内存时,会对地址进行对齐处理。通过`new`分配内存时,分配器自动处理对齐,而对齐通常会导致小量的内存空间未被占用,从而产生一定程度的非连续性。
七、内存碎片问题
在多次`new`和`delete`操作过程中,会产生内存碎片。内存碎片导致大量小块的空闲内存散布在整个地址空间,从而使得连续内存块的分配变得困难。内存分配器有时会合并相邻的小内存块,形成一个较大的空闲区间,以供未来大块内存需求使用。当请求大于任何一个可用的连续小内存块时,分配器会选择这样的合并后的区块,这可能导致`new`操作返回的地址不连续。
结论
C++中新分配的内存地址不连续是一种常见现象,这一点反映了底层系统和运行时环境的复杂性。内存分配过程中的多种因素,如操作系统的虚拟内存管理、内存分配策略、内存对齐和碎片化问题等,共同作用于此。程序员应当意识到这些因素,以便更加高效地进行内存管理和排查潜在的问题。
文章标题:C++ 中多次 new 的地址为什么不是连续的,发布者:worktile,转载请注明出处:https://worktile.com/kb/p/67955