首页 > 其他 > 详细

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

时间:2021-01-16 22:00:09      阅读:23      评论:0      收藏:0      [点我收藏+]

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

技术分享图片

  如果C语言基础较好的话,对上面也比较好理解。

  但是再看到下面:

技术分享图片

  以及再下面:

技术分享图片

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

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

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

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

1. 什么是指针?

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

  如下图:(请原谅我拙劣的画图水平,拿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行中所调用的。

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

原文:https://www.cnblogs.com/Dreaming-in-Gottingen/p/14287296.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!