首先看一串代码
#include <stdio.h> #include <stdlib.h> void main(){ int *p1 = (int *)malloc(4); int *p2 = (int *)malloc(4); int *p3 = (int *)malloc(4); int *p4 = (int *)malloc(4); printf("p1 = %p\n",p1); printf("p2 = %p\n",p2); printf("p3 = %p\n",p3); printf("p4 = %p\n",p4); }
可见每次开辟的空间之间间隔16字节(p2-p1等于16字节),而每次开辟的空间明明只有4字节,多余的12字节从何而来?
原因在于,malloc开辟的内存空间位于堆,堆是由链表维护的,链表的每个结点(结构体)由两部分组成:“数据部分”、“控制部分”。所以对于上面的情况多余的12字节来自于控制部分,并与内存对齐有关。控制部分主要包括上一个结点的地址、下一个结点的地址、当前结点的空间大小等。
在Linux系统中,运行着一个进程,会在"/proc/进程ID"下保存进程运行时所有的信息,进程结束时该文件夹会自动删除。
Linux的内存结构可以分为以下几个部分。
代码段、数据段、BSS段、堆、栈
对于一个空的main函数:
#include <stdio.h> #include <stdlib.h> void main(){ }
现在在代码中插入一个局部常量
#include <stdio.h> #include <stdlib.h> void main(){ const int a = 3; }
没有变化,因为局部常量位于局部栈中。
在代码中插入一个全局常量
#include <stdio.h> #include <stdlib.h> const int b = 3; void main(){ }
代码段增加了4个字节变成1037,所以全局常量位于代码段。
#include <stdio.h> #include <stdlib.h> int a=1; static b=2; const int c = 3; void fun(){ } void main(){ int a1 = 1; static int b1 = 2; const int c1 = 3; printf("a = %p\n",&a); printf("b = %p\n",&b); printf("c = %p\n",&c); printf("a1 = %p\n",&a1); printf("b1 = %p\n",&b1); printf("c1 = %p\n",&c1); printf("fun = %p\n",fun); printf("main = %p\n",main); }
查看/proc目录下进程中的maps文件
总结:
代码区:存放的CPU的机器指令、全局常量、字符串常量。
数据段:存储初始化的全局变量、静态变量。
BSS段:未初始化的全局变量、静态变量。
堆:动态开辟的内存空间。低地址向高地址扩展
栈:局部变量、局部常量。高地址向低地址扩展
malloc与new的区别:
new的实现是利用malloc,但是在malloc后会初始化空间。
如果是基本数据类型,直接初始化为默认值
如果是UDT,调用对应的构造函数进行初始化。
与内存分配有关的函数:
(1)malloc:
(2)void * calloc(int count , int size):count为元素个数,size为每个元素的大小。分配count*size字节的空间,并初始化。
(3)alloca:原型类似malloc,但在栈中分配空间、
(4)void * realloc(void * ptr , int new_size): 修改已经配置好的内存空间大小,ptr为待修改的空间地址,new_size为新的内存大小。
若内存减少:则直接返回ptr,内存空间大小变为new_size
若内存增加:若后续空间足够,则返回ptr,内存空间变为new_size。若后续空间不足,则寻找第一个能够满足条件的空间,并将数据拷贝到新内存空间,返回新空间地址。
注:ptr = realloc(ptr , new_size)是不对的,如果分配失败,ptr变为NULL,则原空间不能访问。