我也要学C语言-第二十三章:微软未公开的堆内存

Posted on 2011-07-05 10:09  dodolook  阅读(8116)  评论(76编辑  收藏  举报
int main(int argc, char *argv[], char *envp[])
{
int a =1;
int b =2;

return0;
}

在这个代码中,变量a和b还有3个参数都在栈中,那么在栈里面分配的空间有什么特点的呢?!它们在编译器编译期限就为它们预留了空间。那么还有一个堆空间,它和栈空间有什么区别呢?!其实堆空间是在程序运行过程中,你需要什么就找它要什么。打个比方,就好像你去逛超市,你去之前你想买什么,你在脑子里面都已经想好了,到了超市你直接把你需要东西都买啦!这时候你买的这些东西一般都在栈中。但是你在超市里或者看到你当时还没有想买的又很想吃的东西呢,你肯定就再买啦!但是这些东西都是你出门前没有想到的东西,这时候你就需要另外规划钱了,你就再多计划点钱了,但是你身没带那么多钱怎么呀!你就去借点,在计算机中就是找操作系统去借啦!然后去买啦!这时候,这些东西一般就在堆中。而且在计算机里,你就需要向操作系统说,我还要点东西,呵呵!但是找操作系统再要内存,不一定要得到啊,有时候万一没有了呢,所以要内存的时候就需要做1个检查。因为是找操作系统借的,所以当用完了后还需要还给操作系统!如果不还就不行啊,因为你不还,大家也都不还,这样内存就耗尽了,就会出问题了。到底我们如何简单分辨到底在堆中还是栈中呢?!只要我们把握好申请内存的时机,计划内的就在栈,计划外的就在堆。另外要注意一个问题,堆栈是指的栈,和堆没关系。这就好比韩信好佩刀剑,其实他就是佩的剑。

C语言库中操作堆的2个函数malloc和free 

malloc这个函数就是找操作系统申请内存,这个函数是这样定义的:

void *malloc(size_t size);    Required Header[<stdlib.h> and <malloc.h>] 

首先,这个函数是个C标准的库函数,当你使用malloc的时候,你不需要关系找操作系统申请内存的具体流程。否则你要用一个当地平台的API去申请内存。malloc.h相当于1个中介所呢!

如何使用malloc

  首先你要包含库,stdlib.h或者malloc.h. 你在调用此函数的时候,你需要提供size_t类型的size. size_t其实就是int.然后返回值是一个void *. void *是一个指针,设计malloc的人无法知道你是把这段内存干嘛用呢?!所以只能返回void *啦!所以你用的时候就要进行一次强制转换,转换成你所设计的使用。

malloc是借,free是还

  嘿嘿!你向操作系统借了东西,是要还的啊!操作系统就相当于上帝,你欠上帝的始终都要还的,呵呵!

free的定义:void free(void *memblock);

当你还内存的时候,你就需要告诉它你要还什么,这个*memblock参数就是申请到的内存首地址。

程序实例:

int main()
{
int*pInt = NULL;//必须先初始化为NULL,
pInt = (int*)malloc(sizeof(int));//一定要转换哦!不然报错!强制为你所 设计的

if(NULL == pInt)//必须做检查,检查申请成功了没,如果申请成功返回首地址,不成功就返回NULL也就是0。
{
return-1;//这里设置成你的合适的处理方式,不一定是退出。
}

if(pInt)//在释放之前必须做检查。
{
free(pInt);
pInt
= NULL;//释放完了以后必须再次设置为NULL,杜绝野指针。
}

return0;
}

我们来看看,我们的堆空间到底是什么样子的。

这里看到了1个以前没有看到过的地址段,0x003706e0。这个应该就是操作系统分配的堆空间的地址,这个地址我们从内存中可以看到1些特点.在调试版下,它有一些结构去辅助程序的调试。我们看到这里地址值被初始化为CD,在栈空间是初始化的CC。哦!原来是这样,那么我们以后只要看到CD了,就知道是调试版的啦!然后再单步一下,值就赋为7了。

内存泄漏

(上面截图有个书写错误,就是sizeof(char)应该是sizeof(char[]))这个程序正确的吗?我们仔细一瞧,不对呀!0x0042028是只读数据区的地址呀!这样的话,就是说,Ipstr的值被覆盖了,这样的话,原来的内存就无法释放了,这样的话就叫内存泄漏了。这样的话free的时候就要出错啦!为什么会出错啊,就是因为释放了1个常量。

以后千万不要犯这样的错误啊!那么要怎么写才对呢?!我们这里就要用到1个函数啦!:strcpy(lpstr, "Hello world");

但是还是有个问题,就是这里只是1个记录,要是我要把1千万个学生放如内存,如何去释放呢,我相信继续学习后某天一定会知道的了。

刚才程序报错,为什么它知道我们释放的不是堆内存呢?!进一步调试下,

因为堆内存都微软没有公开的资料,所以很多堆的特性都是通过逆向工程,和通过前辈高人的研究成果。堆很有特点:

1:首先调试版下,初始化为全CD

2:前后4个FD,防止溢出,如果FD被破坏,调试版的时候会给警告

3:堆是一个双项链表结构,在当前堆指针减16的地方就到了堆的数据长度,这就是为什么后面FD位置的确定

4:这个是和操作系统版本相关的,以上适合于WINDOWS XP

5:如果FD被破坏了,你可以手工修复,程序一样可以正确运行