C++内存管理

C++内存管理 #

1、new/delete 和 malloc/free 有什么区别? #

  1. new 的步骤分两步:调用 malloc 申请空间、调用构造函数。释放空间的时候一样。
  2. new 不需要头文件, malloc 要 stdlib.h
  3. 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 实现方案 #

系统调用开销 + 内存碎片 => 采用内存池。

  1. 将内存分成大小不同的 chunk, 通过 bins 组织起来
  2. 128 个bin,分为 small bins(每个chunk相同)、large bins(不同)、unsorted bin(相当于缓冲区
  3. 如果要的内存 <512 字节 => small, 否则 large, 否则 unsorted_list
  4. 如果全都不够,< 128k => brk 否则mmap

3、如果 new / malloc 返回空指针,怎么办? #

  • new:会抛出异常,可以用 try…catch
  • malloc:要判断是否空指针,是的话就return终止

4、遇到过内存泄露吗?内存泄露了怎么办? #

几种可能:

  1. 未成对出现,申请了没有释放的操作。比如在构造中申请,析构中没释放。
  2. 没有将基类的析构函数定义为虚函数。
  3. 没有定义拷贝构造函数 或者 没有重载赋值运算符,导致两次释放的相同的内存。类中包含指针变量。

工具:linux 下 valgrind、mtrace等工具。

6、C++有哪几种内存分配方式? #

  1. 在栈上:函数,局部变量
  2. 堆上:动态内存分配 new/malloc
  3. 全局/静态存储区
  4. 常量存储区

7、堆和栈的区别?动态分配内存和静态分配内存的区别 #

  1. 分配方式不同:动态,由程序员控制 VS 静态,编译器自动管理
  2. 碎片:有 VS 无
  3. 生长方向:从低->高 VS 反过来

#33 8、浅拷贝和深拷贝的区别?

  • 浅:只赋值指针,和原来的指向同一块内存
  • 深:创建一个新的一样的对象。

9、结构体内存对齐了解吗? #

结构体中会按size最大的成员对齐。

智能指针 #

0、智能指针概念 #

  1. 用途是用于动态分配内存,防止内存泄露和空悬指针问题。
  2. 原理是将基本类型指针封装为类对象指针,离开作用域->调用析构,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统计在内。