JM8.6以内存分配——基础篇

  在研究JM8.6中内存分配模块(memalloc.c)时,看到以下代码:算法

  若是C语言基础较好的话,对上面也比较好理解。函数

  可是再看到下面:工具

  以及再下面:布局

  可真得花点时间去琢磨内存如何布局的,以及如何访问到指望位置的值。spa

  本篇文章就准备将背景知识和上面的三个内存分配函数,介绍一下,以供有此困惑的人来理解。3d

  其实,很早以前就有该想法,针对C语言的指针来作一次科普,但因为拖延症的缘故一直没动笔。指针

  本篇是基础篇,后面会再开一篇来介绍上面三个函数的原理及内存布局。code

1. 什么是指针?blog

  所谓指针,就是某个地址空间,存储着一个值(指针值),这个值为某个内存地址。内存

  以下图:(请原谅我拙劣的画图水平,拿win10自带的绘图工具画的。。。)

  

  拿32位系统来进行说明,每一个指针(无论什么类型的指针——内置类型或自定义类型)的sizeof都为4Bytes,而且为

了高效访问,通常都是4字节对齐的(存储ptr值的这段内存地址addr2,打印其值,最后两个二进制位为0)。

  上图中,内存空间addr2中存储着一个指针值——ptr(ptr的值为addr1),即这个ptr指针指向addr1这个地址空间。

2. 栈指针 & 堆指针

  计算机系统中两种内存类型——stack和heap,stack为栈内存,如函数内临时变量、函数参数,heap为堆内存,如malloc

分配的空间,其从系统中获取,通常分配和回收使用伙伴算法(buddy)。

  其中stack增加方向向下,heap增加方向向上,以下demo及打印:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void stack_test()
 5 {
 6     int tmp0;
 7     int tmp1;
 8     int tmp2;
 9     printf("stack_addr: &tmp0=%p, &tmp1=%p, &tmp2=%p\n", &tmp0, &tmp1, &tmp2);
10 }
11 
12 void heap_test()
13 {
14     char *ptr0 = (char*)malloc(64);
15     char *ptr1 = (char*)malloc(64);
16     char *ptr2 = (char*)malloc(64);
17     printf("heap_addr: ptr0=%p, ptr1=%p, ptr2=%p\n", ptr0, ptr1, ptr2);
18 }
19 
20 int main(void)
21 {
22     stack_test();
23     heap_test();
24 }

  从运行结果看,tmp0~2这种stack变量的地址,从高地址往低地址变化,而ptr0~2这种指向heap空间的值,从低往高变化。

然而,ptr0~2做为stack类型变量,其地址仍符合stack的增加方向(从高往低变化)。不信能够打印出&ptr0, &ptr1, &ptr2的值。

3. 如何给一个指针变量赋值?

  使用以下方式:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void mem_alloc(char **pp)  5 {  6     *pp = (char*)malloc(64);  7 }  8 
 9 int main() 10 { 11     char *ptr0; 12     char *ptr1; 13     char *ptr2; 14 
15     char ch = 'A'; 16     ptr0 = &ch;                 //ptr0指向stack变量ch
17     ptr1 = (char*)&ptr2;        //ptr1指向ptr2这个stack变量的地址
18     mem_alloc(&ptr2);           //给ptr2这个stack变量赋值,赋值为heap空间地址
19     printf("stack_addr: &ptr0=%p, &ptr1=%p, &ptr2=%p, &ch=%p\n", &ptr0, &ptr1, &ptr2, &ch); 20     printf("ptr_val: ptr0=%p, ptr1=%p, ptr2=%p\n", ptr0, ptr1, ptr2); 21 }

  须要注意一点的是,若是经过函数调用给一个变量初始化,那么参数必须是该变量的地址,如18行的:mem_alloc(&ptr2);

  为何?

  传地址才能修改该地址处的值(ptr2这个stack变量的内存地址空间中,所保存的值——指向哪儿),而传值只是进行了一份数据拷贝,

等调用的函数退出后,原先被拷贝的变量什么都没改变。

  所以,若是想修改15行中ch这个stack变量的值,就传其地址:&ch;若是想修改13行的ptr2这个stack变量的值,也传其地址:&ptr2,

正如18行中所调用的。

4. 指针、双指针、三指针、四指针

  指针也能够称为单指针,相似于这种:void* ptr; 如上面代码中的ptr0,ptr1,ptr2。

  双指针为指向指针的指针,相似于:void** pptr; 如第4行中的形参:void mem_alloc(char **pp)。

  三指针其实又多了一个*,形如:void*** ppptr; 能够理解为一个指针指向一个双指针,而该三指针变量值(该变量内存空间中的值)为第一个指针值。

  四指针也又多了一个*,形如:void**** pppptr; 再多一道中转。

  画个图来表达:

  

   其中,存储字符的空间我故意画小,由于其大小为1Byte,而指针的大小为4Bytes。

相关文章
相关标签/搜索