C语言面试高频(内存)
内存
1 请说说内存分布模型⭐⭐⭐⭐⭐
如上图,从低地址到高地址,一个程序由代码段、数据段、BSS段、堆栈段组成。
1.代码段:存放程序执行代码的一块内存区域。只读,不允许修改,代码段的头部还会包含一些只读的常量,如字符串常量字面值(注意:const变量虽然属于常量,但是本质还是变量,不存储于代码段)。
2.数据段data:存放程序中已初始化的全局变量和静态变量的一块内存区域。
3.BSS 段:存放程序中未初始化的全局变量和静态变量的一块内存区域。
4.可执行程序在运行时又会多出两个区域:堆区和栈区。
堆区:动态申请内存用。堆从低地址向高地址增长。
栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。
5.最后还有一个文件映射区(共享区),位于堆和栈之间。
2 堆和栈的区别⭐⭐⭐⭐⭐
1.堆栈空间分配不同。栈由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等,栈有着很高的效率;堆一般由程序员分配释放,堆的效率比栈要低的多。
2.堆栈缓存方式不同。栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放;堆则是存放在二级缓存中,速度要慢些。
3.空间大小: 栈的空间大小并不大,一般最多为2M,超过之后会报Overflow错误。堆的空间非常大,理论上可以接近3G。(针对32位程序来说,可以看到内存分布,1G用于内核空间,用户空间中栈、BSS、data又要占一部分,所以堆理论上可以接近3G,实际上在2G-3G之间)
4.能否产生碎片: 栈的操作与数据结构中的栈用法是类似的。‘后进先出’的原则,以至于不可能有一个空的内存块从栈被弹出。因为在它弹出之前,在它上面的后进栈的数据已经被弹出。它是严格按照栈的规则来执行。但是堆是通过new/malloc随机申请的空间,频繁的调用它们,则会产生大量的内存碎片。这是不可避免地。
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内存管理原理⭐⭐⭐⭐⭐
Malloc函数用于动态分配内存。为了减少内存碎片和系统调用的开销,malloc其采用内存池的方式,以此来减少内存碎片,先申请大块内存作为堆区,然后将堆区分为多个内存块,以块作为内存管理的基本单位。当用户申请内存时,直接从堆区分配一块合适的空闲块。Malloc采用隐式链表结构将堆区分成连续的、大小不一的块,包含已分配块和未分配块;同时malloc采用显示链表结构来管理所有的空闲块,即使用一个双向链表将空闲块连接起来,每一个空闲块记录了一个连续的、未分配的地址。
当进行内存分配时,Malloc会通过隐式链表遍历所有的空闲块,选择满足要求的块进行分配;当进行内存合并时,malloc采用边界标记法,根据每个块的前后块是否已经分配来决定 是否进行块
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
该专栏面向嵌入式开发工程师、C++开发工程师,包括C语言、C++,操作系统,ARM架构、RTOS、Linux基础、Linux驱动、Linux系统移植、计算机网络、数据结构与算法、数电基础、模电基础、5篇面试题目、HR面试常见问题汇总和嵌入式面试简历模板等文章。超全的嵌入式软件工程师面试题目和高频知识点总结! 另外,专栏分为两个部分,大家可以各取所好,为了有更好的阅读体验,后面会持续更新!!!