- 分配内存的位置
- malloc是从
堆
上动态分配内存 - new是从
自由存储区
为对象动态分配内存。自由存储区的位置取决于operator new的实现。自由存储区不仅可以为堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存
- 是否可以被重载
- opeartor new 、operator delete 可以被重载
- malloc、free则不能重载
- 内存分配
- malloc内存分配成功后返回void*,然后再
强制类型转换为需要的类型
- malloc内存分配失败后返回 NULL
- new操作符分配内存成功后返回与对象类型相匹配的指针类型;因此new是符合类型安全的操作符
- new分配内存失败则会抛异常 std::bad_alloc
- 如果加上
std::nothrow
关键字`,UserInfo* info = new (std::nothrow) UserInfo; // new 就不会抛出异常而是会返回空指针
- 分配内存的大小的计算
- 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息
自行计算
- malloc则需要
显式
地指出所需内存的尺寸
- 使用场景
- new/delete 适用于C++对象,它们会自动处理对象的构造和析构。
- malloc/free 更通用,可以在C++中使用,也可以在C中使用,但需要手动管理对象的构造和析构。
UserInfo* user = static_cast<UserInfo*>(malloc(sizeof(UserInfo)));
new (user) UserInfo("Alice", 25);
std::cout << "User's age: " << user->getAge() << std::endl;
user->~UserInfo();
free(user);
- Malloc 函数用于动态分配内存。为了减少内存碎片和系统调用的开销,malloc 其采用内存池的方式,先申请大块内存作为堆区,然后将堆区分为多个内存块,以块作为内存管理的基本单位。
- 当用户申请内存时,直接从堆区分配一块合适的空闲块。
- Malloc 采用隐式链表结构将堆区分成连续的、大小不一的块,包含已分配块和未分配块;同时 malloc 采用显示链表结构来管理所有的空闲块,即使用一个双向链表将空闲块连接起来,每一个空闲块记录了一个连续的、未分配的地址。
- 当进行内存分配时,Malloc 会通过隐式链表遍历所有的空闲块,选择满足要求的块进行分配;当进行内存合并时,malloc 采用边界标记法,根据每个块的前后块是否已经分配来决定是否进行块合并。
- Malloc 在申请内存时,一般会通过brk或者mmap 系统调用进行申请。其中当申请内存小于128K 时,会使用系统函数brk 在堆区中分配;而当申请内存大于128K 时,会使用系统函数mmap 在映射区分配。
void* operator new(size_t size) {
std::cout << "Custom new called. Size: " << size << std::endl;
void* memory = std::malloc(size);
if (!memory) {
throw std::bad_alloc();
}
return memory;
}
void operator delete(void* ptr) noexcept {
std::cout << "Custom delete called." << std::endl;
std::free(ptr);
}
int main() {
Data* data = new Data();
delete data;
return 0;
}