C++ new 操作符在操作系统层执行了什么操作?
在C++中,new操作符的执行涉及操作系统层面的内存分配和对象构造过程,具体可分为以下几个关键步骤:
1. 调用内存分配函数(operator new)
new操作符首先通过operator new函数向操作系统申请内存。该函数底层通常调用malloc或类似的系统调用(如brk/mmap),从堆空间分配指定大小的内存块。若内存不足,默认会抛出std::bad_alloc异常。
2. 计算所需内存大小
根据对象类型(内置类型或自定义类),new会计算所需内存大小,包括考虑内存对齐和类成员变量的空间占用。对于数组,还需额外存储数组大小信息以便后续析构。
3. 调用构造函数初始化对象
内存分配成功后,new会在该内存上调用对象的构造函数完成初始化。对于自定义类型,构造函数负责初始化成员变量;内置类型(如int)则直接赋初值。
4. 返回对象指针
最终,new返回指向已构造对象的指针,供程序使用。若构造函数抛出异常,已分配的内存会自动释放以避免泄漏。
5. 与malloc的底层区别
malloc仅通过brk(小内存)或mmap(大内存)系统调用分配虚拟内存,而new还包含构造步骤。 new失败时抛出异常,malloc返回NULL;new支持重载operator new实现自定义分配策略。
操作系统交互示例
小内存(<128KB):通过brk调整堆顶指针_edata,延迟分配物理内存(首次访问时触发缺页中断)。
大内存(≥128KB):通过mmap在文件映射区域分配虚拟内存。
综上,new的操作系统交互核心是通过operator new触发底层内存分配系统调用,并协调构造/析构语义,确保类型安全。
问题思考:
1. 系统调用brk 和 mmap 有什么不同?
2. new 为数组开辟内容空间的时候,数组大小这个额外的信息是如何存储的? int * p = new int[5]; 指针p 指向的的int 数据地址还是数组大小的地址?
3. new 是可以被重载的,能否为特定的类设计对象池分配策略?
4. new 失败时会抛出异常, 能否改造不抛出异常?