内存管理(一)new 和 delete 底层实现

    技术2026-04-08  10

    前言

    最近在看侯捷老师的内存管理这门课,整理一下课程中的知识和自己的思路。

    正文

    1.new

    在c++的使用中,我们使用new手动申请堆区内存。下面看一下new到底干了什么。 举个例子: Complex * pc = new Complex(1,2); 这行代码是使用new创建一个Complex型的对象。 在底层编译器实际上是完成下面的事情:

    Complex *pc; try { void* tmp = operator new(sizeof(Complex)); // 调用operator::new 分配内存 pc = static_cast<Complex*>(tmp); //转换类型 pc->Complex::Complex(1,2); // 调用构造函数(这种形式是编译器实现的形式,只有部分平台可以直接以这种形式调用构造函数) } catch(std::bad_alloc) { // 内存分配失败就不执行构造函数 }

    所以我们看到了,调用new表达式会执行两个步骤: 1.调用operator::new 分配内存 2.调用构造函数 需要注意的是,如果内存分配失败,会抛出异常,将不会调用构造函数。 那么operator::new 干了什么?

    void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) { if (_callnewh(size) == 0) { _THROW_NCEE(_XSTD bad_alloc, ); } } return (p); }

    我们看到,operator::new 实际上是调用了 malloc函数,并且如果malloc失败,会调用callnewh,如果成功,则会再malloc一次,否则抛出异常。 那么callnewh实际上就是调用new_handler(当内存分配失败时的回调函数),我们可以在函数中自己设定功能(比如释放掉一些无关紧要的内存,或结束程序等等)。当进行这些处理后如果还是分配失败,就说明真的没有内存给它分配了,就抛出异常。 可以使用_set_new_handler来设定callnewh所调用的函数。 总结: 1.调用operator::new函数申请空间(operator::new 调用 malloc函数),申请失败抛出异常。 2.调用static_cast将空间的类型转换为目标类型。 3.调用构造函数(简单数据类型不需要)。

    2.delete

    举同一个例子: delete pc;

    pc->~Complex(); operator delete;

    先是调用了对象的析构函数,然后调用operator::delete。

    void operator delete(void *p) { free(p); }

    由operator::delete调用free来释放内存。

    总结: 1.调用对象析构函数(简单数据类型不需要)。 2.调用operator::delete函数(operator::delete 调用 free)。

    Processed: 0.012, SQL: 9