C++内存管理
有关C++内存管理问题总结如下
基础问题
C++
中堆和栈的区别是什么
- 栈由系统分配释放,栈上变量的生命周期是确定的,一般与作用域有关。栈的地址由高到低,栈上分配的空间大小在编译时通常已知。
- 堆由程序员手动开辟释放,堆上的变量除非被显示释放,否则会持续存在。堆的地址由低到高,堆上几乎可以分配任意大小的内存块,但可能会造成内存碎片。
- 这里说一下
C++
的内存分区:堆区、栈区、data
区、bss
段、代码段。数据data
区存放的是静态变量和初始化的全局变量,bss
段存放的是未初始化的全局变量。
什么是RAII
?为什么它在C++
中很重要
RAII
是一种编程思想和设计模式,核心思想是:将资源的获取与对象的初始化捆绑在一起,将资源的释放与对象的销毁捆绑在一起。这样,资源管理就与对象的生命周期紧密关联。
1 |
|
解释new
和delete
,与malloc
和free
的区别
属性的区别
new/delete
:这两个是C++
中的关键字;malloc/free
:这两个是库函数;使用上的区别
malloc
:申请空间需要显式填入申请内存的大小;new
:无需显式填入申请内存的大小,new
会根据new
的类型分配内存;返回类型的区别
new
操作符内存分配成功,返回的是对象类型的指针,类型严格与对象匹配,无需进行类型转换,故new
是符合类型安全性的操作符。malloc
内存分配成功返回的是void*
指针,需要通过强制类型转换,转换成我们需要的类型。所以
C++
中new
比malloc
安全可靠。分配失败的区别
malloc
分配失败会返回NULL
,我们可以通过判断返回值是否是NULL
得知是否分配成功。new
分配失败会抛出bad_alloc
异常。扩张内存的区别
malloc
有内存扩张机制(通过realloc
实现)。new
没有扩张内存机制。
中级问题
为什么C++
推荐使用智能指针,如shared_ptr
和unique_ptr
- 自动管理内存:对于
unique_ptr
,当它超出作用域或者被重新分配时,它指向的对象会被删除。对于shared_ptr
,当它的引用计数为0时,它指向的对象会被删除。 - 异常安全:当函数抛出异常,智能指针确保资源被正确清理,避免资源泄露。
- 防止悬挂指针:悬挂指针是指指向已经释放内存的指针。
unique_ptr
和shared_ptr
可以减少悬挂指针的风险,因为他们确保在没有引用的时候释放资源。
你能解释shared_ptr
中的引用计数机制是如何工作的吗
- 通过一个指针实现引用计数功能,加锁,保证线程安全
什么情况下会导致内存泄漏,你如何检测和预防
指针重新赋值
1
2
3
4int *p = new int();
int *np = new int();
p = np;
//p原来的指向的内存无法释放,因为现在没有指针指向这块内存错误的内存释放
假设有一个指针
p
指向10字节的内存,该内存的第三个字节np
又指向某个动态分配的内存, 如果此时你直接delete(p)
,则会导致np
指向的内存无法释放。返回值的不正确处理
1
2
3
4
5
6
7
8
9int *f(){
return new int(42);
}
void f1(){
f();
}
//由于没有对函数f()的返回值做正确接收,将会导致f函数分配的内存无法释放。
关于内存泄露可以使用工具:Valgrind
。