代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作――它是不可写的。
数据段:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配[1]的变量和全局变量。
BSS段:BSS段包含了程序中未初始化的全局变量,在内存中 bss段全部置零。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
栈:栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
内存分布图(图上框大小不代表内存大小,只是分布):
对于以上内容有点经验的兄弟们都很清楚。那我们为什么还是要深入研究它的存储方式呢?我又不去写操作系统。
以前老员工经常跟我说,了解这些后,可以入手优化代码,提高CPU效率、节省内存。如今做个小通信设备CPU都是1G,可支持内存2G了,而且价格不高。
哎,对编码人是好事还是坏事?但一类问题是CPU和内存等硬件无法帮你解决的,那就是你写代码留下的bug,而且还是一个低概率bug。
以个人遇到的实际问题
1:内存泄露;
2:内存重复释放;
3:内存内容被非法制修改引起异常;
4:栈溢出。
.....太多了。每次遇到这种情况,我就想念java等高级语言。
内存泄露我一直认为是个很简单的东西,分配了就要释放,但这个问题却一直被很多人埋坑。
业务逻辑复杂后,不是你不想释放,是你想不到在哪里释放。
泄露的内存就是在堆中,定位问题时就必须去堆分布段中查找内存是哪个任务malloc.
关于堆内存的管理有很多种算法,另开篇幅介绍。
栈的理解比堆更重要,因为栈承载任务运行以及运行过程中的数据管理。
在系统初始化时,系统会给每个任务分配一个独立的栈空间。
程序运行,函数的调用,局部变量定义,函数返回等都是在此任务独立的栈空间内完成。
如果是从事C语言开发,我认为研究函数调用时栈的产生和恢复,并研究透传,绝对是上层的内功心法,并让你有一种豁然开朗的感觉。