malloc负责在堆上申请一块内存并返回一个指向该内存块的 void 类型的指针, free负责释放掉该指针指向的内存块。
需要明白的是 malloc 申请了多少,free 的时候就强制释放多少,不管该内存块是否是连续的。
例如
//我先申请一个内存块,大小是 100MB
void *memory = malloc(1024 * 1024 * 100);
//现在我可以在这两个字节中任意的放东西了。那我就先放进去一个 string
//需要知道的是string在不同编译器中的长度是不一样的,windows 下的 VS2005 中 ,sizeof(string) = 32
//SunOS 5.8下的 G++ 中,sizeof(string) = 4
string *s = new (memory)string("123456789");
//此时的内存块中前4(32)个字节被利用起来,后面将近100MB的空间都是空闲的。
//s指针指向的地址跟 memory 指向的地址是相同的( memory 的首地址没有改变)
//那此时我释放掉该内存块
free(memory);
delete s;
//两条语句执行哪个都不会出现内存错误(内存访问错误),千万别两条语句一起用,那肯定出错。就算是在战争中,战败的一方也只投向一次,内存也是这样的。free(memory) 释放掉了这100MB的内存,那 delete s 呢?测试之后发现它也是释放掉了这 100MB 的内存。区别是delete会去执行 s 的析构函数,而 free 不会。
//另外一种情况:memory 申请的内存小于 new 出来的内存大小。例如
void *memory = malloc(1);
string *s = new (memory)string("123456789");
//这样就出现了内存越界,结果是不可预测的,什么情况都有可能发生。
//此时的 free(memory) 只删除了一个字节,delete s 同样也是。
其实我们可以把 new delete 看成是 mallco free 的封装,编译器在我们遇见 new 的时候会自动的生成 mallco 代码,然后再调用构造函数,遇见 delete 的时候先执行析构函数然后执行 free(当然编译器还做了更多的事情)。所以在内存越界的时候我们对界外的数据无能为力,那些数据也就成了潜在的危险。运气好的话可以像世外桃源一样悠哉悠哉,赶上光景不好的时候要不覆盖掉别人要不就被别人覆盖。不同的编译器对于越界的处理也不同,就拿上面的简单的代码来说,在VS2005(VC8.0)下运行时(释放的时候)才会报错,而在 G++ 下则没有问题。
再找个例子
//申请两个字节
void *memory = malloc(2);
//从 memory 的首地址开始创建1000个整形数组并给各元素进行赋值
int num = 1000;
int *s = new (memory)int[num];
for(int i = 0; i < num ; i++)
{
cout << "i = " << i << endl;
s[i] = i;
}
delete s;
对于这段代码 i 的最大值能为 1000 吗?这种越界的问题很难判断的,我在VS2005下 i 最大值到了 94 (在我的测试用例中),但是在G++ 下却能到 999,而且 delete s 也没有出错。在 Lniux 下用 KDEV 也能到 999,但是在 delete s 的时候会出错。不知道 G++ 是不是在编译的时候做过了一些优化处理,这个还要研究一下。