跳转至

1. C++是如何做内存管理的

(1),使用malloc、free 动态分配和释放空间,能分配较大的内存; (2),为函数的局部变量分配内存,能分配较小的内存; (3)全局/静态存储区,用于存储全局变量和静态变量; (4)常量存储区,专门用来存放常量; (5)自由存储区:通过new 和 delete 分配和释放空间的内存,具体实现可能是堆或者内存池

2.为什么栈的运行速度更快?

这里说的 “堆” 和 “栈”,并不是 数据结构 上的Heap跟Stack,而是程序运行中的不同内存空间。(例如C++的内存四区:代码区、全局区、堆、栈)

  1. 申请速度快:栈是程序运行前就已经分配好的空间,所以运行时分配几乎不需要时间。而堆是运行时动态申请的,相当于将分配内存的耗时由编译阶段转嫁到了机器运行阶段,将分配过程从编译器搬到了运行的代码中。于是动态分配的速度不仅与分配算法有关,还与机器运行速度有关。(栈是编译时分配空间,而堆是动态分配(运行时分配空间),所以栈的申请速度快)
  2. 存储寻址速度快:栈的物理地址空间是连续的,而堆未必,查找堆的链表也会耗费较多时间,所以存储寻址速度慢。
  3. CPU 硬件操作速度快:cpu 有专门的寄存器(esp,ebp)来操作栈,堆是使用间接寻址的,所以栈快。

2. 栈溢出常见问题

  1. 局部数组过大。当函数内部的数组过大时,有可能导致堆栈溢出。局部变量是存储在栈中的,因此这个很好理解。解决这类问题的办法有两个,一是增大栈空间,二是改用动态分配,使用堆(heap)而不是栈(stack)。
  2. 递归调用层次太多。递归函数在运行时会执行压栈操作,当压栈次数太多时,也会导致堆栈溢出。
  3. 指针或数组越界。这种情况最常见,例如进行字符串拷贝,或处理用户输入等等。

堆和自由存储区的区别与联系

从技术上来说,堆(heap)是 C 语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用 malloc()时就会从中分配,稍后调用 free 可把内存交还。而自由存储是 C++中通过 new 和 delete 动态分配和释放对象的抽象概念,通过 new 来申请的内存区域可称为自由存储区。基本上,所有的 C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符 new 和 delete 也许会按照 malloc 和 free 的方式来被实现,这时藉由 new 运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。 - 堆是 C 语言和操作系统的术语、是操作系统维护的一块内存,而自由存储是 C++中通过 new 与 delete 动态分配和释放对象的抽象概念。堆与自由存储区并不等价。 - new 所申请的内存区域在 C++中称为自由存储区。藉由堆实现的自由存储,可以说 new 所申请的内存区域在堆上。

堆和栈的区别

  • 管理方式:对于栈来讲,是由编译器自动管理无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生 memory leak。
  • 空间大小堆基本没啥限制 4G,栈 1M。一般来讲在 32 位系统下,堆内存可以达到 4G 的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,默认的栈空间大小是 1M(VS2017 项目-属性-链接器-系统可以修改)。
  • 碎片问题:对于堆来讲,频繁的 malloc/free 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。栈是先进后出的队列,以至于永远都不可能有一个内存块从栈中间弹出。
  • 分配方式:
    • 堆都是动态分配的,没有静态分配的堆
    • 栈有 2 种分配方式:静态分配和动态分配
      • 静态分配是编译器完成的,比如局部变量的分配
      • 动态分配由 alloca 函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现
  • 分配效率:
    • 栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高
    • 堆则是 C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
  • 总结一下:
    • 堆中的内存需要手动申请和手动释放,栈中内存是由OS 自动申请和自动释放
    • 堆能分配的内存较大(4G(32 位机器)),栈能分配的内存较小(1M);
    • 在堆中分配和释放内存会产生内存碎片,栈不会产生内存碎片;
    • 堆的分配效率低,栈的分配效率高;
    • 堆地址从低向上,栈由高向下。

2. new/delete 和 malloc/free

(1)new 分配内存空间无需指定分配内存大小,malloc 需要;

(2)new 返回类型指针,类型安全,malloc 返回 void,再强制转换成所需要的类型*;

(3)new 是从自由存储区获得内存,malloc 从堆中获取内存

(4)对于类对象,new 会调用构造函数和析构函数,malloc 不会(核心)

3.内存对齐

  • 原因:关键在于 CPU 存取数据的效率问题。为了提高效率计算机从内存中取数据是按照一个固定长度的。比如在 32 位机上,CPU 每次都是取 32bit 数据的,也就是 4 字节;若不进行对齐,要取出两块地址中的数据,进行掩码和移位等操作,写入目标寄存器内存,效率很低。内存对齐一方面可以节省内存,一方面可以提升数据读取的速度;

*