C++内存管理 #
1、new/delete 和 malloc/free 有什么区别? #
- new 的步骤分两步:调用 malloc 申请空间、调用构造函数。释放空间的时候一样。
- new 不需要头文件, malloc 要 stdlib.h
- new 是类型安全的,比如 int *p = new float[2]就会报错;malloc 不是,编译时可以通过。
2、malloc和free的原理 #
2.1 进程的地址空间 #
- 3 - 4G 内核空间
- 0 - 3G 用户空间
- 栈(↓):局部变量、函数参数、返回地址
- 内存映射段(↓):动态库/匿名映射
- 堆(↑):
- BSS段:未初始化/初始为0的..
- 数据段:初始化的全局变量和局部静态变量
- 代码段:可执行二进制代码
2.2 进程控制块里的mm_struct #
- start_brk:堆的起始地址
- brk:终止地址
- 可以增大brk的值,但需要系统调用
2.3 malloc 实现方案 #
系统调用开销 + 内存碎片 => 采用内存池。
- 将内存分成大小不同的 chunk, 通过 bins 组织起来
- 128 个bin,分为 small bins(每个chunk相同)、large bins(不同)、unsorted bin(相当于缓冲区
- 如果要的内存 <512 字节 => small, 否则 large, 否则 unsorted_list
- 如果全都不够,< 128k => brk 否则mmap
3、如果 new / malloc 返回空指针,怎么办? #
- new:会抛出异常,可以用 try…catch
- malloc:要判断是否空指针,是的话就return终止
4、遇到过内存泄露吗?内存泄露了怎么办? #
几种可能:
- 未成对出现,申请了没有释放的操作。比如在构造中申请,析构中没释放。
- 没有将基类的析构函数定义为虚函数。
- 没有定义拷贝构造函数 或者 没有重载赋值运算符,导致两次释放的相同的内存。类中包含指针变量。
工具:linux 下 valgrind、mtrace等工具。
6、C++有哪几种内存分配方式? #
- 在栈上:函数,局部变量
- 堆上:动态内存分配 new/malloc
- 全局/静态存储区
- 常量存储区
7、堆和栈的区别?动态分配内存和静态分配内存的区别 #
- 分配方式不同:动态,由程序员控制 VS 静态,编译器自动管理
- 碎片:有 VS 无
- 生长方向:从低->高 VS 反过来
#33 8、浅拷贝和深拷贝的区别?
- 浅:只赋值指针,和原来的指向同一块内存
- 深:创建一个新的一样的对象。
9、结构体内存对齐了解吗? #
结构体中会按size最大的成员对齐。
智能指针 #
0、智能指针概念 #
- 用途是用于动态分配内存,防止内存泄露和空悬指针问题。
- 原理是将基本类型指针封装为类对象指针,离开作用域->调用析构,delete
、都有哪些智能指针? #
- shared_ptr
- 多个智能指针可以共享同一个对象。
- 每个share_ptr都有一个关联的引用计数,一旦一个share_ptr的引用计数变为0,就会自动释放自己所管理的对象。
- share_ptr p = make_shared(42);
- unique_ptr
- 独享所有权,保证同一时间只有一个智能指针指向该对象。当unique_ptr被销毁时,指向的独享被释放。
- 不能直接拷贝或赋值。
- unique_ptr p (new string(“unique”));
- weak_ptr
- 可以绑定到share_ptr,指向由shared_ptr管理的对象,允许共享但不拥有。
- 解决share_ptr相互引用时,死锁。
- 在确定是否应该释放对象的时候,shared_ptr不把weak_ptr统计在内。