首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
AI 模拟面试
简历
求职
学习
基础学习课
实战项目课
求职辅导课
专栏&文章
竞赛
搜索
我要招人
发布职位
发布职位、邀约牛人
更多企业解决方案
AI面试、笔试、校招、雇品
HR免费试用AI面试
最新面试提效必备
登录
/
注册
一勺西瓜
重庆邮电大学 嵌入式软件开发
发布于重庆
关注
已关注
取消关注
@keke小牛:
嵌入式八股之c语言内存管理相关
由gcc编译的C语言程序占用的内存分为哪几个部分映射区存储动态链接以及mmap函数进行的文件映射堆区提供程序员动态申请的空间全局(静态区)存放全局变量和静态变量,已初始化的全局变量和静态变量、const型常量在一块区域(.data段),未初始化的、初始化为0的全局变量和静态局部变量在相邻的另一块区域(.bss段)常量区字符串、数字等常量存放在常量区。const修饰的全局变量存放在常量区程序代码区存放函数的二进制代码和字符常量代码段和数据段属于静态内存,堆栈属于动态内存静态内存的特点:各个变量的地址在编译期间就确定了,在程序运行中不再改变动态内存的特点:在程序运行期间内存不固定在可执行文件内不给BSS段分配存储空间,在 程序运行内存时再分配存储空间和地址。堆区和栈区栈区栈有两种基本操作:入栈(push)和出栈(pop)。入栈是把一个 栈元素压入栈中,而出栈则是从栈中弹出一个栈元素。入栈和出栈都 靠栈指针(Stack Pointer,SP)来维护,SP会随着入栈和出栈在栈顶上下移动C语言函数中的局部变量、传递的实参、 返回的结果、编译器生成的临时变量都是保存在栈中的。在很多嵌入式系统的启动代码中,系统 一上电开始运行的都是汇编代码,在跳到第一个C语言函数运行之前, 都要先初始化栈空间。栈的初始化其实就是栈指针SP的初始化,在Linux环境下,栈的起始地址一般就 是进程用户空间的最高地址,紧挨着内核空间,栈指针从高地址往低 地址增长Linux默认给每一个用户进程栈分配8MB大小的空间每一个函数都会有自己专门的栈空间来保存这些 数据,每个函数的栈空间都被称为栈帧(Frame Pointer,FP)。每一 个栈帧都使用两个寄存器FP和SP来维护,FP指向栈帧的底部,SP指向 栈帧的顶部。上一级函 数栈帧的起始地址,即栈底也会保存到当前函数的栈帧中,多个栈帧 通过FP构成一个链,这个链就是某个进程的函数调用栈。很多调试器 支持回溯功能,其实就是基于这个调用链来分析函数的调用关系的。当要传递的参数个数小于4时,直接使用R0~R3寄存 器传递即可;当要传递的参数个数大于4时,前4个参数使用寄存器传 递,剩余的参数则压入堆栈保存。参数传递时按照从右到左的顺序 依次压入堆栈.堆区堆是Linux进程空间中一片可 动态扩展或缩减的内存区域,一般位于BSS段的后面。堆内存是匿名的,不能像变量那样使用名字直接访问,一般通 过指针间接访问。在函数运行期间,对函数栈帧内的内存访问也不能像变量那样 通过变量名直接访问,一般通过栈指针FP或SP相对寻址访问。堆内存由程序员自己申请和释放,函数退出时,如果程序员没 有主动释放,就会造成内存泄漏。在裸机环境下一片连续的堆内存空间,经过多次小块内存的申请 和释放后,就会造成内存碎片化,malloc()/free()函数的底层实现,其实就是通过系统调用brk向 内核的内存管理系统申请内存。内核批准后,就会在BSS段的后面留出 一片内存空间,允许用户进行读写操作大于128KB,一般会通过mmap系 统调用直接映射一片内存,使用结束后再通过ummap系统调用归还这块 内存堆内存分配当用户申请一块内存时,内存分配器就根据申请的内存大小 从 bins 查 找 合 适 的 内 存 块 。 当 申 请 的 内 存 块 小 于 M_MXFAST 时 , ptmalloc分配器会首先到fast bins中去看看有没有合适的内存块,如 果没有找到,则再到small bins中查找如果要申请的内存块大于512 字节,则直接跳过small bins,直接到unsorted bin中查找内存分配器如果在unsorted bin中没有找到合适 大小的内存块,则会将unsorted bins中物理相邻的内存块合并,根据 合并后的内存块大小再迁移到small bins或large bins中防止栈溢出尽量不要在函数内使用大数组,如果确实需要大块内存,则可 以使用malloc申请动态内存。函数的嵌套层数不宜过深。递归的层数不宜太深。堆区和栈区主要区别:• 申请方式:栈区内存由系统自动分配和释放,函数结束时释放;堆区内存由程序员自己申请,并指明大小,用户忘释放时,会造成内存泄露,不过进程结束时会由系统回收• 申请后系统的响应:栈只要有剩余空间就能提供内存,否则报异常;堆则要先在自由链表中找到足够大的空间再分配给程序 。堆区和栈区出现数组越界,各自的表现如下:• 栈上数组越界:可能会覆盖其他变量或者返回地址等重要信息,导致程序崩溃或者被攻击。• 堆上数组越界:可能会破坏堆管理器的数据结构,导致后续分配或者释放出错或者失败。• 空间大小:栈区空间通常有一个限制,比如8MB;堆区空间一般比较大,受限于操作系统的有效虚拟内存。• 碎片问题:栈使用是先进后出的顺序,不会产生碎片;堆频繁地分配和释放可能会造成碎片,使得效率降低。在堆区分别申请两个1个字节的内存,其内存空间不一定会连续。因为堆区的内存分配是在逻辑地址上是连续的,但在物理地址上是不连续的 。堆区的内存分配还要考虑自由链表中是否有足够大的空间 。如果没有,可能会导致分配失败或者产生碎片。• 生长方向:栈向低地址扩展;堆向高地址扩展。当在堆区和栈区出现数组越界时,它们表现出的情况有所不同。堆区:运行时错误(Runtime Error):在堆区动态分配的数组,如果越界访问了数组元素,通常不会导致直接的崩溃或错误。这是因为在堆区分配的内存是由程序员负责管理的,操作系统不会对越界进行保护。程序可能会继续执行,但是访问到越界的内存可能导致不可预测的行为,可能会覆盖其他内存区域的内容,导致程序在后续执行中出现错误。内存损坏或泄漏:当在堆区进行数组越界访问时,可能会修改或破坏堆区中其他动态分配的内存块,导致内存损坏。另外,如果越界访问导致程序丢失对已分配内存的指针,可能会导致内存泄漏,因为程序无法正确释放这部分内存。栈区:栈溢出(Stack Overflow):在栈区分配的数组,如果越界访问了数组元素,可能会导致栈溢出。栈区是由编译器自动管理的,通常有固定的大小限制。当递归调用层数过多或者在函数内部使用大型数组时,栈的空间可能会耗尽,导致栈溢出错误,进而导致程序崩溃。运行时错误(Runtime Error):与堆区类似,栈区中的数组越界访问不会直接导致程序崩溃。程序可能会继续执行,但是访问到越界的内存可能导致不可预测的行为,因为栈区的越界访问也会影响到栈帧中其他的局部变量和返回地址等。在遇到数组越界问题时,不同编程语言和环境可能表现不同,有些语言可能会提供一定的越界检查机制,而有些则不会。为了避免这类问题,程序员应该在编程时注意数组的边界,并确保进行正确的边界检查,以保证程序的稳定性和安全性。程序a调用程序b ,栈有什么变化当程序a调用程序b时,栈会发生变化。程序a的栈帧会被压入栈中,然后程序b的栈帧被压入栈中。在程序b执行完后,程序b的栈帧会被弹出,然后程序a的栈帧也会被弹出。在调用函数时,参数和返回地址都会被压入栈中。函数执行完后,返回地址会被弹出,然后函数的返回值也会被压入栈中。堆栈溢出一般是由什么原因导致的?堆栈溢出一般包括堆内存溢出和栈内存溢出,两者都属于缓冲区溢出。堆内存溢出可能是堆的尺寸设置得过小/动态申请的内存没有释放。栈内存溢出可能是栈的尺寸设置得过小/递归层次太深/函数调用层次过深/分配了过大的局部变量。静态链接和动态链接静态链接如果我们在项目中引用了库函数, 则在编译时,链接器会将我们引用的函数代码或变量,链接到可执行 文件里,和可执行程序组装在一起,这种库被称为静态库缺点1: 如果在一个源 文件中我们定义了100个函数,而只使用了其中的1个,那么链接器在 链接时也会把这100个函数的代码指令全部组装到可执行文件中,这会 让最终生成的可执行文件体积大大增加,解决办法:我们在封装函数库时,将每个函数都 单独使用一个源文件实现,然后将多个目标文件打包即可缺点2:如C标准库里的printf()函数, 可能多个程序都调用了它,链接器在链接时就要将printf的指令添加 到多个可执行文件中。在一个多任务环境中,当多个进程并发运行 时,你会发现内存中有大量重复的printf指令代码,很浪费内存资源动态链接动态库在编译阶段不参与链接,不会和可执行文件组 装在一起,而是在程序运行时才被加载到内存参与链接,因此又叫作 动态链接库。优点:节省了内存资源:加载到内存的动态链接库可 以被多个运行的程序共享,使用动态链接可以运行更大的程序、更多 的程序,升级也更加简单方便。在Linux环境下,当我们运行一个程序时,操作系统首先会给程序 fork一个子进程,接着动态链接器被加载到内存,操作系统将控制权 交给动态链接器,让动态链接器完成动态库的加载和重定位操作,最 后跳转到要运行的程序。动态链接器在C标准库中实现,是glibc的一 部分,主要完成程序运行前的动态链接工作。动态链接器本身也是一个动态库, 即/lib/ld-linux.so文件。动态链接器被加载到内存后,会首先给自 己重定位,然后才能运行。像这种自己给自己重定位然后自动运行的 行为,我们一般称为自举动态链接需要考虑的一个重要问题是加载地址。动态链接库的地址要根据进程地址空间 的实际空闲情况随机分配。很容易想到的一个方法就是装载时重定位。想让我们的动态库放到内存的任何位置都可以运行,都可以被多个进程共享一种比较好的方法是将我们的动态库设计成与地址无关的代码,将指令中需要修改的部分(如对绝对地址符号的引用)分离出来,剩余的部分就和地址无关了,放到哪里都可以执行。以ARM平台为例,可 以采用相对寻址来实现延迟绑定:程序在 运行时,并不急着把所有的动态库都加载到内存中并进行重定位。当 动态库中的函数第一次被调用到时,才会把用到的动态库加载到内存 中并进行重定位问题1:但是当动态库作为第三方模块被不 同的应用程序引用时,库中的一些绝对地址符号(如函数名)将不可避免地被多次调用,需要重定位。动态库中的这些绝对地址符号,如何能做到同时被不同的应用程序引用解决办法:每个应用程序将引用的 动态库(绝对地址)符号收集起来,保存到一个表中,程序在运行过程中需要引用这些符号时, 可以通过这个表查询各个符号的地址,这个表为全局偏移表(GOT)。根据动态 库被加载到内存中的具体地址,更新GOT表中的各个符号(函数)的地 址。等下次该符号被引用时,程序可以直接跳到GOT表查询该符号的地 址,如果找到要调用的函数在内存中的实际地址,就可以直接跳过去 执行了动态链接和静态链接,分别用在哪些场景下1. 静态链接(Static Linking):在静态链接中,链接器将所有需要的目标文件和库文件的代码合并到一个单独的可执行文件中。这意味着可执行文件独立于系统上的其他库文件,它包含了所有程序运行所需的代码和数据。当程序被静态链接后,它可以在其他没有相关依赖的系统上运行,因为所有依赖项都已包含在可执行文件中。适用场景:独立可执行文件:静态链接生成的可执行文件可以在目标系统上独立运行,无需依赖其他外部库文件。这对于需要分发给其他用户或部署到不同环境的应用程序很有用。性能优化:静态链接可以在编译时将所有库文件和目标文件合并,这可能会提高程序的执行性能,因为在运行时不需要再进行动态加载和链接。版本控制:使用静态链接可以确保应用程序使用特定版本的库,减少由于不同版本库文件导致的不兼容性问题。2. 动态链接(Dynamic Linking):在动态链接中,程序在运行时仅保留对外部库函数的引用,并没有将实际代码合并到可执行文件中。相反,程序在运行时会从系统共享库(动态链接库或共享对象文件)中加载所需的函数。这意味着同一共享库可以被多个程序共享,节省内存空间,并且库的更新只需要替换共享库文件而不需要重新编译程序。适用场景:共享库的使用:动态链接适用于使用大型通用库的情况,这样多个程序可以共享同一个库,减少内存占用和二进制文件大小。库的更新和维护:动态链接使得库的更新更加方便,只需替换共享库文件,而不需要重新编译所有使用该库的程序。节省内存空间:多个程序使用同一个共享库时,动态链接可以节省内存空间,因为共享库的代码只需要在内存中加载一次。总体而言,静态链接适用于需要独立分发的程序或对性能优化有较高要求的场景,而动态链接适用于共享大型通用库、节省内存和方便库的更新维护的场景。编译时出现ld的报错,问题出在哪里未找到目标文件:链接器无法找到需要合并的目标文件。请确保所有源文件都已正确编译为目标文件,并在编译命令中正确指定它们的路径。重复定义符号:如果多个目标文件中出现了同名的全局变量或函数,链接器会报重复定义的错误。解决方法是确保每个符号只定义一次,并使用extern关键字声明其他地方引用的全局变量或函数。缺少依赖库:如果程序依赖于外部库,但链接器无法找到所需的库文件或库函数,将会报错。此时,您可以通过在编译命令中添加库文件路径或使用-l参数指定库来解决问题。缺少主函数:如果程序缺少main函数作为入口点,链接器将无法生成可执行文件。请确保每个源文件中都包含一个名为main的函数作为程序的入口。内存泄漏没有使用free()函数及时 地 将 这 块 内 存 归 还 给 内 存 分 配 器 ptmalloc 或 内 存 管 理 子 系 统 , ptmalloc和内存管理子系统就失去了对这块内存的控制权失去管理和追踪的这块内存,一直孤零零地躺在内存的某片区域,用户、内存分配器和内存管 理子系统都不知道它的存在,它就像内存中的一块漏洞,我们称这种 现象为内存泄漏。泄漏原因使用malloc,realloc函数后,没有通过free函数将内存释放掉内存泄漏检测:Mtrace它通过跟踪内存的使用记录 来动态定位用户代码中内存泄漏的位置。使用MTrace很简单,在代码 中添加下面的接口函数就可以了#include<mcheck.h>void mtrace(void);void muntrace(void);//mtrace()函数用来开启内存使用的记录跟踪功能,muntrace()函 数用来关闭内存使用的记录跟踪功能通过生成的日志文件mtrace.log来定位内存泄漏在程序中的位 置Linux内核模块运行机制而内核模块的运行不依赖C标准库,动态链接、重定 位过程需要内核自己来完成当我们使用insmod命令加载一个内核模块时,基本流程如下(1)kernel/module.c/init_module.(2)复制到内核:copy_module_from_user。(3)地址空间分配:layout_and_allocate。(4)符号解析:simplify_symbols。(5)重定位:apply_relocations。(6)执行:complete_formation。malloc和new的区别语法不同:malloc是C语言中的函数,需要手动指定分配内存的大小,并且返回的是void*类型的指针;而new是C++中的运算符,可以根据类型自动计算分配内存的大小,并且返回的是具体类型的指针。构造函数的调用:使用malloc分配的内存只是简单的分配了一块内存空间,不会调用对象的构造函数;而使用new分配的内存会调用对象的构造函数,完成对象的初始化。内存分配失败处理:malloc在内存分配失败时会返回NULL,需要手动判断是否分配成功;而new在内存分配失败时会抛出std::bad_alloc异常,可以使用try-catch来捕获异常。内存释放方式不同:malloc分配的内存必须使用free函数手动释放;而new分配的内存可以使用delete运算符来释放,同时会调用对象的析构函数来完成资源的释放。
点赞 4
评论 0
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
04-22 15:50
长沙理工大学 C++
双非本211硕,华为OD干安卓1年半转正无望想跳槽,该继续安卓、转后端还是冲全栈?
网友提问:yt大佬你好,我是24届毕业生,双非本211硕。当年毕业选择了出生地的电信市公司,但由于种种原因离职了,现在在华为od干安卓开发。现在一年半了。目前薪资上勉强看的过去,基本月薪是18k,总包税前是差不多30万的样子。准备年中再和leader谈一波涨薪,然后准备跳槽。跳槽的原因很简单就是工资还是相对正编来说太低了。毕竟od不是长久之地,od的涨薪确实是太慢了,没有什么未来,转华为正式员工这两年由于人太多,机会约等于0。导致上限锁死在d5,上限太低。不过od一般来说确实不会被裁,相对正编要稳定点,毕竟是性价比很高的工具人。组里有蛮多比领导呆的久的od老人的。和很多人一样都是我也是被从ja...
点赞
评论
收藏
分享
昨天 12:58
门头沟学院 Java
4.28 用友(java后端实习)面经
bg:双非学院本0实习一、自我介绍二、项目拷打Q1:请介绍一下你简历中的项目,挑一个几个你认为做得比较好的地方讲讲。(问了好多拷打了好多)三、八股(格外的少)居然是在会议评论区出的题(第一次见)Q2:HashMap是不是线程安全的、会出现什么问题、你怎么处理的Q3:Synchronize和ReetrantLock区别Q4:数据库索引作用、索引失效的情况(三个就行)、explain怎么看用没用到索引四、场景题(可以写伪代码或者口述 口述了)Q5:1.设计一个泛型类有key和value 2.保证并发安全的同时3.设置限流 5秒五次4.设计一个缓存 最大容量100 超过采取lru删除五、反问环节问了...
查看8道真题和解析
点赞
评论
收藏
分享
03-01 02:29
四川大学 Java
26春招
润色了一下,这个简历还有救吗,春招还能上岸吗😭经历秋招洗礼,感觉运气&gt;&gt;实力
wannasleep:
二哥项目😁
点赞
评论
收藏
分享
04-11 10:15
已编辑
腾讯_后台开发(实习员工)
28届双非本腾讯开发实习oc
如题,tl:3.3 投递3.9 一面3.17 二面3.25 三面3.26 hr面4.1 offer给同样面了腾讯的同志们一点参考。说好的字节才是双非友好大厂呢,为什么我简历是投一次锁一次,以后要当节恨子!鹅是人生第一次面试,本来以为要挂几次,没想到流程还算顺利,初面就直接给我过了,我要感谢腾讯,感谢面试官,感谢hr,感谢所有人。真心是体会到了,找日常实习就是七分运气三分实力。鹅的黑卡有点帅
喵_coding:
666,28届开挂了
我的OC时间线
点赞
评论
收藏
分享
04-22 09:22
武汉大学 C++
双非还有机会吗?搞硬件也开始乞讨了?
前言上数十年,今年是招聘环境最差的一年,但下数十年,今年有可能是招聘环境最好的一年。——来源秋招中遇到的不知名的某hr找工作本身就是运气+实力,甚至在菜鸡看来运气占比更高,有的时候不要总是怪自己(倒也不是为自己开脱哈),尽人事听天命,不要自己内耗。菜鸡在这里总结一下自己的整个一个找工作情况,一方面是从群众中来到群众中去,感谢找工作的时候中各位大佬们的资料与建议;另一方面是希望能为更多的小伙伴们提供微不足道的帮助。一、楼主自己情况菜鸡自己是来源于东三省某双非大学(排名很低的那种),本硕自动化,硕士研究方向是纯仿真(跟控制和编程无任何关系),无正式实习(导师派出去干过杂活),无高水平期刊论文,无高...
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
点赞
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
求问:有没有真的能上手做大模型/Agent的实战项目?
1.3W
2
...
【春招】巨人网络发offer啦!
1.3W
3
...
Agent面试-RAG篇
6966
4
...
毕业季有感
3882
5
...
暑期实习0进展
3678
6
...
腾讯云智二面挂
2437
7
...
【暑期实习】腾讯音乐二面🧑🏻💻
2278
8
...
社招面经
1965
9
...
wxg timeline
1965
10
...
五月还找不到暑期就完蛋了...吗?
1888
创作者周榜
更多
正在热议
更多
#
这个offer值得去吗?
#
1989次浏览
29人参与
#
你实习是赚钱了还是亏钱了?
#
116757次浏览
632人参与
#
联宝杯大学生创新大赛,你的技术值得产业级答案
#
42824次浏览
496人参与
#
你会因为行情,降低找工作标准吗?
#
8997次浏览
89人参与
#
想做Agent可以做哪些岗位?
#
2337次浏览
27人参与
#
如果春招能重来,我会___
#
4433次浏览
52人参与
#
面试官拷打AI项目都会问什么?
#
1829次浏览
91人参与
#
你觉得最好用的AI编程工具是_
#
919次浏览
24人参与
#
除了线上,还能去哪些地方投简历
#
3100次浏览
34人参与
#
实习想申请秋招offer,能不能argue薪资
#
253791次浏览
1311人参与
#
你和你的mentor相处模式是__
#
5810次浏览
46人参与
#
实习第一天,你在干什么
#
3684次浏览
26人参与
#
如何排解工作中的焦虑
#
326577次浏览
2802人参与
#
mt对你说过最有启发的一句话
#
115158次浏览
872人参与
#
暑假倒计时,你都干了些啥?
#
58856次浏览
313人参与
#
美的求职进展汇总
#
374336次浏览
2079人参与
#
你的mentor是什么样的人?
#
61618次浏览
796人参与
#
大疆求职进展汇总
#
703232次浏览
4353人参与
#
金融银行面经
#
109053次浏览
557人参与
#
0offer互助地
#
777085次浏览
4783人参与
#
0经验如何找实习?
#
90846次浏览
944人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务