1、brk释放内存和sbrk分配内存
#include<unistd.h>
int brk(void *end_data_segment);
成功返回0,否则为-1
将内存边界设置为参数所指定位置
void *sbrk(intptr_t increment);
成功返回之前的内存边界,失败返回(void*)-1
增加内存边界,返回为新分配内存的起始位置(sbrk(0)就是获得堆位置)
使用的例子
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
int* phead; // 指向首位置
int* pnow; // 指向当前指针位置
pnow = sbrk(0); // 先分配空闲区域
phead = pnow; // 固定首位置不变
for(int i=2; i<10000; i++)
{
if(isPrime(i)) // 该函数用于判断是否是素数(忽略)
{
brk(pnow+1);// 分配4个字节(1个int)
*pnow = i; // 存入数据
pnow = sbrk(0); // 指向系统指针上次移动到的那个位置
}
}
pnow = phead; // 从头打印
while(pnow!=sbrk(0))
{
cout <<*pnow<<endl;
pnow++;
}
brk(phead); // 释放空间
}
二、malloc和free使用
#include<stdlib.h>
void *malloc(size_t size);
成功返回分配的首地址,失败返回NULL
void free(void *ptr);
若无法分配内存,或者因为已经抵达内存边界所能达到的地址上限,则malloc返回NULL,所以一定要进行malloc返回值的错误检查。
free函数并不降低内存边界的位置,而是将这块内存添加到空闲的内存列表中,供后续的malloc循环使用。
说清楚点就是free并不是把栈的地址的内容给清零,而是告诉系统栈的某块内容可以被使用而已。如果够不告诉系统,则表明该区域一直在使用(实际上已经不使用了)。那么系统在做下一次new或者malloc的操作的时候就会开辟另一个空间。但是栈空间是有限的,如果一直没有free那么这个栈就会溢出。
注意:
如char pt=(char )malloc(10*sizeof(char));
需要free(p)才会释放空间。
如果free的参数不是当时malloc返回的地址,就会出现如图的错误(改了很久的bug 2333)
三、malloc和free的实现
出现上图改了很久之后,我就在想,为什么一定要free参数是malloc的返回值,查了系统编程之后看到一张图就明白很多了。
当malloc分配内存块的时候,会额外分配几个字节来存放记录这块内存大小的整数值。该整数位于内存块的起始处,而malloc返回的是内存块之后的位置(箭头的位置)。free就去查找这个内存头的具体信息,来进行对malloc数据的释放,所以free的参数一定要传对,不然free就会出现严重的错误!!!
四、calloc
#include<stdlib.h>
void *calloc(size_t numitems,size_t size);
成功返回创建的初始地址,并且初始化内存为0,失败返回NULL
char pt==(char )calloc(100, sizeof(char));
然后用calloc开辟的空间其内容会自动初始化为空,等于把该栈中使用的空间清零。也就是赋值’\0’。(因为是char,所以是\0)。也需要用free来对该空间进行释放
五、realloc
#include<stdlib.h>
void *realloc(void *ptr,size_t size);
成功返回指向大小调整后内存块的指针,失败返回NULL
注意:
①调用relloc(ptr,0)等效于在free(ptr)之后调用malloc(0)
②若ptr为NULL,则realloc(NULL,size)相当于调用malloc(size)
③realloc增加了已分配的内存块的大小,则不会对额外分配的字节进行初始化。
④如果原来内存块位于堆的顶部,那么realloc将对堆空间进行拓展。如果内存块位于堆的中部,且紧邻其后的空闲内存空间大小不足,realloc会分配一块新内存,将原来数据复制到新内存块中,占用大量cpu时间,不推荐使用!
⑤扩充内存之后,原来指向内存的指针都用可能不能用,最好使用加偏移量的方式重新定位
char pt=(char )malloc(10*sizeof(char));
realloc(pt, 1000*sizeof(char));
六、alloca从栈上分配内存
#include<alloca.h>
void *alloca(size_t size);
成功返回已经分配内存的指针
注意:
①alloca相当于分配在栈上,到时候会自动销毁,不能在定义的函数之外使用。
②alloca是最特殊的开辟栈空间方法,优点是当离开调用这个函数的时候,栈所分配的空间会自动释放(也就是free)。
③alloca不能在函数的参数中使用,因为函数参数位于栈帧固定位置。
//错误
func(x,alloca(size),x)
//正确
void funcA(void)
{
void *y;
y = alloca(size);
funcB(x,y,z);
}
//当funcA返回的时候,y才销毁
④因为编译器会将alloca作为内联代码处理,并通过直接调整堆栈指针来实现。
七、内存泄露
做malloc类似的开辟空间的操作之后,当不使用的时候不做释放结果导致一直占据该内存单。(用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。)栈将稳步增长,直至抵达可用虚拟内存的上限,在之后分配内存的任何尝试都将以失败告终。