面试题答案
一键面试1. malloc和new在底层内存分配机制上的差异
- 内存分配方式:
- malloc:
malloc
是C标准库函数,它从堆(heap)上分配内存。其基本工作原理是向操作系统请求一块指定大小的连续内存空间。操作系统维护一个记录空闲内存块的链表,malloc
遍历该链表,寻找一个大小足够的空闲块。如果找到,就将该块标记为已使用,并返回指向该块起始地址的指针。如果找不到合适大小的块,可能会尝试扩展堆空间(通过系统调用,如brk
或mmap
,具体取决于操作系统)。 - new:
new
是C++的关键字,它不仅分配内存,还会调用对象的构造函数。在底层,new
首先调用operator new
函数(通常可以重载)来分配内存,operator new
本质上也是通过调用malloc
或类似的底层内存分配函数来从堆上获取内存。不同之处在于,new
在获取内存后会根据对象类型调用相应的构造函数进行初始化。
- malloc:
- 与操作系统内存管理的交互:
- malloc:直接依赖操作系统提供的内存分配函数,如在Linux下通过
brk
或mmap
系统调用与内核交互来获取和管理堆内存。它不了解对象的类型信息,只是单纯地分配指定字节数的内存。 - new:
new
在调用operator new
获取内存后,会根据对象类型进行额外的处理。operator new
调用malloc
获取内存,之后C++运行时系统负责调用对象的构造函数。在释放内存时,delete
调用operator delete
(通常可重载),operator delete
再调用free
来释放内存,并且在释放前会调用对象的析构函数。
- malloc:直接依赖操作系统提供的内存分配函数,如在Linux下通过
2. new确保对象正确构造
new
在分配内存后会自动调用对象的构造函数。例如:
class MyClass {
public:
MyClass() {
// 构造函数的初始化代码
std::cout << "MyClass constructor called" << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor called" << std::endl;
}
};
MyClass* obj = new MyClass();
在上述代码中,new MyClass()
首先调用operator new
分配内存,然后自动调用MyClass
的构造函数,确保对象在创建时被正确初始化。
3. malloc分配内存用于对象存储时开发者需注意的问题
- 手动调用构造函数:使用
malloc
分配内存后,不会自动调用对象的构造函数。例如:
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor called" << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor called" << std::endl;
}
};
MyClass* obj = static_cast<MyClass*>(malloc(sizeof(MyClass)));
if (obj) {
new (obj) MyClass(); // 定位new,手动调用构造函数
}
- 手动调用析构函数和释放内存:使用
malloc
分配的内存,在释放时需要手动调用析构函数,然后再调用free
释放内存。例如:
if (obj) {
obj->~MyClass(); // 手动调用析构函数
free(obj);
}
- 类型安全:
malloc
返回的是void*
类型指针,需要进行显式类型转换,这可能导致类型安全问题。而new
返回的指针类型与对象类型匹配,更安全。
总之,new
和malloc
在内存分配和对象管理上有明显差异,在C++中使用new
能更方便、安全地创建对象,而使用malloc
需要开发者手动处理对象的构造和析构等操作。