堆栈
- 堆 程序员自由挥霍的一大部分内存
- 栈 系统自动管理的一小部分内存
虚拟内存
当今的操作系统都会给每一个进程分配独立的虚拟地址空间
虚拟内存是计算机系统内存管理的一种技术,它使得应用程序认为它拥有连续的可用内存,而实际上,它通常是被分割成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上。在需要时进行数据交换。
内存地址
- 函数 字符串常量
- 静态变量(函数类static变量 文件类的static变量 全局变量)
- 利用malloc分配的内存区域
- 自动变量
函数自身和字符串常量被配置在内存里相邻的地址上(只读区域)
静态变量
静态变量是从程序启动到运行结束为止持续存在的变量,因此静态变量总是在虚拟地址空间上占有固定区域。
包括全局变量,文件内static变量和指定static的局部变量。因为这些变量的有效作用域各不相同,所以编译和链接时具有不同的意义,但是运行的时候都是以相似的方式呗使用。
自动变量
保存在栈,一旦函数执行结束,自动变量的内存区域就会被释放
自动变量属于连接器管辖以外的对象,因为自动变量的地址是在运行时决定。
内存分配
malloc()根据指定的只存来分配内存块,它返回指向内存块初始位置的指针,经常被用于动态分配结构体的内存区域,分配不足返回NULL。
//void*标识泛型指针,可以赋给任何类型的指针变量
void* malloc(size_t size);
//分配1000个字节的堆空间,返回第一个字节的地址
char *p = malloc(1000);
//释放第一个字节的地址为p的堆
free(p);
堆栈区别
int *func(void)
{
int a ;
int *p = malloc(4);
//错误,func函数在执行完成之后,所在的栈的空间被释放,a也被释放
return &a;
//正确,p分配的地址在堆上面,不会随着函数的结束而释放,只有自己释放或者在程序结束后释放。
return p;
}
内存操作函数
//从source指向的位置直接复制num个字节的值到destination指向的内存块。
void * memcpy ( void * destination, const void * source, size_t num );
//从source指向的位置复制num个字节的值到destination指向的内存块。复制操作的发生就好像使用了中间缓存,允许destination和source重叠。
void * memmove ( void * destination, const void * source, size_t num );
//将ptr指向的内存块的前num个字节设置为特定的值value(被解释为一个unsigned char类型的值)
void * memset ( void * ptr, int value, size_t num );
//在ptr指向的内存块的前num个字节中搜索value值得第一次出现(被解释为一个unsigned char类型的值),并返回指向该值的指针。
const void * memchr ( const void * ptr, int value, size_t num );
void * memchr ( void * ptr, int value, size_t num );
//将ptr2指向的内存块的签num个字节与ptr2指向的内存块的前num个字节进行比较,如果它们都相符合则返回0,反之则返回一个指示其中一个较大的非零值。
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
在各个块之前加上一个管理区域,通过管理区域构建一个链表。malloc遍历链表寻找空的块,如果发现尺寸正好能够满足使用的块,就分割出来将其变成使用中的块,并且向应用程序返回紧邻管理区域的后面区域的地址。
free将管理区域的标识改写成空块,顺便也将上下空的块合并成一个块。这样可以防止块的碎片化。
如果不存在足够大的空块,就请求操作系统对空间进行扩容。(unix系统下用brk系统调用)
调用free后,对应的内存区域不会立刻被破坏,而是保留着原来的值,知道某个地方执行malloc(),随着当前内容被重新分配,内容才开始被破坏。
只要使用malloc的内存管理,就无法根本回避碎片化问题。
calloc = malloc + memset
realloc扩展内存区域,如果传递的区域后面有足够大小的空闲区域,就分配给其他新的空间,然后将内容复制过去,如果常用realloc扩展内存区域,而后面没有足够的空间,就会影响运行效率。
不断对内存进行分配,释放的操作会引起内存碎片化。解决的办法是一次性扩容。