1. 堆和栈的区别⭐⭐⭐⭐⭐

  2. 请你说说野指针⭐⭐⭐⭐⭐

  3. 请你说说内存泄露⭐⭐⭐⭐⭐

  4. 在函数中申请堆内存需要注意什么?⭐⭐⭐⭐⭐

  5. 请你说说内存碎片⭐⭐⭐⭐⭐

  6. 请你说说malloc内存管理原理⭐⭐⭐⭐⭐

  7. 什么是内存池⭐⭐⭐⭐⭐

  8. 说说new和malloc的区别,各自底层实现原理⭐⭐⭐⭐⭐

  9. 说说使用指针需要注意什么?⭐⭐⭐⭐⭐

  10. 初始化为0的全局变量在bss还是data⭐⭐⭐⭐⭐

=========================================================================================================

  • 本专栏适合于C/C++已经入门的学生或人士,有一定的编程基础。
  • 本专栏适合于互联网C++软件开发、嵌入式软件求职的学生或人士。
  • 本专栏针对面试题答案进行了优化,尽量做到好记、言简意赅。这才是一份面试题总结的正确打开方式。这样才方便背诵
  • 针对于非科班同学,建议学习本人专刊文章《蒋豆芽的秋招打怪之旅》,该专刊文章对每一个知识点进行了详细解析。
  • 如专栏内容有错漏,欢迎在评论区指出或私聊我更改,一起学习,共同进步。
  • 相信大家都有着高尚的灵魂,请尊重我的知识产权,未经允许严禁各类机构和个人转载、传阅本专栏的内容。

=========================================================================================================

  1. 堆和栈的区别⭐⭐⭐⭐⭐

    图片说明

    1. 堆栈空间分配不同。栈由操作系统自动分配释放 ,存放函数的参数值局部变量的值等,栈有着很高的效率;堆一般由程序员分配释放,堆的效率比栈要低的多
    2. 堆栈缓存方式不同。栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放;堆则是存放在二级缓存中,速度要慢些。
    3. 空间大小: 栈的空间大小并不大,一般最多为2M,超过之后会报Overflow错误。堆的空间非常大,理论上可以接近3G。(针对32位程序来说,可以看到内存分布,1G用于内核空间,用户空间中栈、BSS、data又要占一部分,所以堆理论上可以接近3G,实际上在2G-3G之间)。
    4. 能否产生碎片: 栈的操作与数据结构中的栈用法是类似的。‘后进先出’的原则,以至于不可能有一个空的内存块从栈被弹出。因为在它弹出之前,在它上面的后进栈的数据已经被弹出。它是严格按照栈的规则来执行。但是堆是通过new/malloc随机申请的空间,频繁的调用它们,则会产生大量的内存碎片。这是不可避免地。
  2. 请你说说野指针⭐⭐⭐⭐⭐

    野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

    野指针不同于空指针,空指针是指一个指针的值为null,而野指针的值并不为null,野指针会指向一段实际的内存,只是它指向哪里我们并不知情,或者是它所指向的内存空间已经被释放,所以在实际使用的过程中,我们并不能通过指针判空去识别一个指针是否为野指针。

  3. 请你说说内存泄露⭐⭐⭐⭐⭐

    简单地说就是申请了一块内存空间,使用完毕后没有释放掉。

    (1)new和malloc申请资源使用后,没有用delete和free释放;

    (2)子类继承父类时,父类析构函数不是虚函数。

    (3)比如文件句柄、socket、自定义资源类没有使用对应的资源释放函数。

    (4)shared_ptr共享指针成环,造成循环引用计数,资源得不到释放。

    有以下几种避免方法:

    第一:良好的编码习惯,使用了内存分配的函数,一旦使用完毕,要记得使用其相应的函数释放掉。

    第二:将分配的内存的指针以链表的形式自行管理,使用完毕之后从链表中删除,程序结束时可检查改链表。

    第三:使用智能指针。

    第四:一些常见的工具插件可以帮助检测内存泄露,如ccmalloc、Dmalloc、Leaky、Valgrind等等。

  4. 在函数中申请堆内存需要注意什么?⭐⭐⭐⭐⭐

    (1)不要错误地返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡。即函数内申请的临时数组,不要指望能够拿到数组内的内容,因为函数执行完成后,数组消亡。

    (2)不要返回了常量区的内存空间。因为常量字符串,存放在代码段的常量区,生命期内恒定不变,只读不可修改。不可修改拿到也没有什么意义。

    (3)通过传入一级指针不能解决,因为函数内部的指针将指向新的内存地址。

    解决办法

    (1)使用二级指针

    (2)通过指针函数解决,返回用malloc新申请的堆内存空间的地址,这样才能拿到内存内容。

  5. 请你说说内存碎片⭐⭐⭐⭐⭐

    内存碎片通常分为内部碎片外部碎片

    (1)内部碎片是由于采用固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,通常内部碎片难以完全避免;

    (2)外部碎片是由于某些未分配的连续内存区域太小,以至于不能满足任意进程的内存分配请求,从而不能被进程利用的内存区域。再比如堆内存的频繁申请释放,也容易产生外部碎片。

    解决方法:

    (1)段页式管理

    (2)内存池

  6. 请你说说malloc内存管理原理⭐⭐⭐⭐⭐

    当开辟的空间小于 128K 时,调用 brk()函数;

    当开辟的空间大于 128K 时,调用mmap()。

    malloc采用的是内存池的管理方式,以减少内存碎片。先申请大块内存作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的空闲快。采用隐式链表将所有空闲块,每一个空闲块记录了一个未分配的、连续的内存地址。

  7. 什么是内存池⭐⭐⭐⭐⭐

    内存池也是一种对象池,我们在使用内存对象之前,先申请分配一定数量的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。当不需要此内存时,重新将此内存放入预分配的内存块中,以待下次利用。这样合理的分配回收内存使得内存分配效率得到提升。

  8. 说说new和malloc的区别,各自底层实现原理⭐⭐⭐⭐⭐

    1. new是操作符,而malloc是函数。
    2. new在调用的时候先分配内存,在调用构造函数,释放的时候调用析构函数;而malloc没有构造函数和析构函数。
    3. malloc需要给定申请内存的大小,返回的指针需要强转;new会调用构造函数,不用指定内存的大小,返回指针不用强转。
    4. new可以被重载;malloc不行
    5. new分配内存更直接和安全。
    6. new发生错误抛出异常,malloc返回null
  9. 说说使用指针需要注意什么?⭐⭐⭐⭐⭐

    1. 定义指针时,先初始化为NULL。
    2. 用malloc申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。在现行C++标准中,如C++11,使用new申请内存后不用判空,因为发生错误将抛出异常。
    3. 不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
    4. 避免数字或指针的下标越界,特别要当心发生“多1”或者“少1”操作
    5. 动态内存的申请与释放必须配对,防止内存泄漏
    6. 用free或delete释放了内存之后,立即将指针设置为NULL,防止“野指针”
  10. 初始化为0的全局变量在bss还是data⭐⭐⭐⭐⭐

    BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。

##豆芽点评 所有题都是五颗星,因为内存管理实在太重要了,一定要掌握。面试、笔试最常考。