进程内存使用
进程运行必须占用内存,运行之前就已定义好的即为静态分配,运行时分配的便是动态分配。
5种类型:
1. 代码段 .text
存放指令代码,属性为只读。很多人不理解为什么哈弗结构既然是 .text 和 .data 分离,那只有一个RAM ,怎么解释呢,其实这很简单啊,IA32不是有选择子么
数据段有数据段的选择字,有数据段的属性,代码段有代码段的属性,有它的选择字,ARM 也无非就是将段分成不同的属性来管理,一个介质RAM搞定。
2. 数据段 .data
存放已初始化数据,这个真没啥好说的。
3. BSS段 .bss
存放未初始化全局变量,由此一同事问我,为什么BSS不需要占用 img大小,我想了想,诶,这肯定不占用啊。因为BSS不要像.data 那样有image 数据啊。
如果不明白,可以这么想,既然是未初始化的数据,那么数据原本就是未知的,那么就没有必要保存这个初始化数据了。
例如
static int i = 0x12345678; /* 这里0x12345678保存在可执行镜像 img 文本内 */
static int j ; /* 没有任何的img 数据 */
void x (void)
{
printf ( "%d%d \n",i,j); /* 那么取 j 的时候,就只管在内存中 *(&j) 咯 */
}
虽然是这样,但是未初始化的变量容易出问题,所以很多时候我们必须要清零 bss区,将所有用户”未初始化“数据,初始化一遍,这就是 main 函数前所做的事情了。
4. HEAP 堆
动态分配,往高地址扩展,malloc ,则地址增,free 则地址减。
5. 栈 STACK
又被称作临时数据交换区
在IA(x86)里面,
int a [4];
那么相应的汇编即为 SUB ESP 4 * 4 ; 这里是4个 int 就是 4*4字节;
在ARM 里面就是
int a [4];
汇编就是 SUBS R13,R13,#4*4 ; R13 通常为堆栈指针,仅仅是通常哈!
那么存放的数据是怎么放进去的? 答案是代码里嵌入进去的,比如 堆栈 int a = 0x1234 ,那么在创建堆栈之后,就是 mov [xxxx],0x1234。
函数call / bl 完一般有一个 add(s) ,清除堆栈,因此,如果函数呼叫完,还访问堆栈的数据,不一定是不正确的,但是绝对是不安全的。注意这点就好。
这里还有一个小问题,那就是C 和 ASM 混合使用的时候,C呼叫 ASM 函数,或者 ASM 呼叫 C函数,这里的堆栈使用就很有乐趣了。这涉及到堆栈平衡的问题
在嵌入式里面非常有用的一点就是C呼叫ASM函数了
比如在 asm 里面 push 0x11111111
push 0x222222222
push 0x333333333
call xxx
add esp,0x0C
但是在C 函数xxx ()里可以不一定要写全3个参数,这样我们可以有选择的取参数。
这在ARM 里面非常有用,(ARM 默认 R0 - R3作为前4个参数)
那么在 asm 里面 LDR R0,=0x11111111
LDR R1,=0X22222222
LDR R2,=0X33333333
LDR R3,=0X44444444
BL xxx
SUM :进程内存使用分布图