StriveMario 发表于 2016-9-27 22:59

C语言malloc的内存在堆中存放与管理

在此之前需要了解一个结构体, 它存放了你申请的内存块信息, 与上一个申请的内存块相关联的信息, 操作系统对堆内存的申请和释放都需要通过这个结构体来获取信息而这个结构体就存放在malloc所申请返回的指针上面,而malloc申请返回的指针也是这个结构体的结束地址

原型如下:


typedef struct _CrtMemBlockHeader
{
    struct _CrtMemBlockHeader * pBlockHeaderNext;//下一个结构体指针
    struct _CrtMemBlockHeader * pBlockHeaderPrev;//上一个结构体指针
    char *                      szFileName; //文件名
    int                         nLine;      //代码行数
    size_t                      nDataSize;//数据空间的大小(字节)
    int                         nBlockUse;//块类型 1是自己调用 2为库函数调用 0为未调用
    long                        lRequest;   //堆申请次数
    unsigned char               gap; //溢出标志
    /* followed by:
    *unsigned char         data;      //数据空间
    *unsigned char         anotherGap;//溢出标志
    */
} _CrtMemBlockHeader;

了解之后我们尝试着申请一个结构体, 然后到内存中看看是什么样子


申请一个结构体, 并malloc一块内存

typedef struct stStuden
{
    char szName;
    int nNum;
    int nAge;
}stu;

stu * pSt = (stu *)malloc(sizeof(stu));

这时候把返回的指针拉到内存窗口, 向上拖动就可以看到这个结构体的内容

http://hd.tuzi123.com/11884/photo/Mon/2016/09/176230_68361474986675888a60701c97454.png

A区就是CrtMemBlockHeader结构体, 0043d108 这是下一个结构体内容 pBlockHeaderNext00000000 因为是最后申请的结构体了, 所以为上个结构体为空 pBlockHeaderPrev00000000 自己malloc的堆内存是没有名字和行数的, 所以为空 szFileName00000000      参照上行 nLine00000010 申请的堆空间大小,大小为0x10   nDataSize01000000 块类型, 1为代码申请, 2为编译器申请, 0为释放状态nBlockUse00000084 堆的序号, 也是申请次数,第0x84ci申请堆空间lRequestfdfdfdfd   溢出标志, 该位置被改变, 释放空间时会崩溃 gap;
B区就是所申请的内存空间在Debug版本下, 申请的堆的可使用空间是用 ”CD” 符号填充的, “FD” 符号来防止越界, 在释放之后会使用 “EEFE” 符号来表示该区域是没有使用的区域

我们可以跟进到pBlockHeaderNext所指向的结构体中, 看看内存情况

http://hd.tuzi123.com/11884/photo/Mon/2016/09/176230_8d31147498703664cb78978d73f10.png

这次可以发现pBlockHeaderPrev正好是指向我们之前申请的那块内存的_CrtMemBlockHeader的结构体头部, 这似乎很像链表
而这次nBlockUse 的值为02 , 这是一个库函数malloc的一块内存, 并且名字和行数的指针有了数据
申请的大小为0x3e, 是第0x83次申请,通过跟上图对比我们可以了解到很多信息


了解完这些信息就可以试试代码遍历现在的堆了, 通过pBlockHeaderNext访问相邻的结构体, 通过来判断是否为空为结束, 以此来作为条件循环读取每个结构体的信息


代码如下:


_CrtMemBlockHeader*pHead = (_CrtMemBlockHeader*)pSt - 1;//获取结构体指针位置

    while (pHead != NULL)
    {
      printf("szFileName:%snLine:%d nDataSize:%d nBlockUse:%d "
            "lRequest:%d stAdddress:%p DataAdddress:%p\r\n",
            pHead->szFileName,
            pHead->nLine,
            pHead->nDataSize,
            pHead->nBlockUse,
            pHead->lRequest,
            pHead,
            pHead + 1);//指针+1等于加上指针类型的大小

      pHead = pHead->pBlockHeaderNext; //把下一个结构体指针给pHead
    }

    //释放
    if (pSt != NULL)
    {
      free(pSt);
      pSt = NULL;
    }

运行结果:
http://hd.tuzi123.com/11884/photo/Mon/2016/09/176230_145e1474988093884d8087e185955.png

可以清楚的看到现在程序中堆的情况
PS: stdenvp这货申请那么多空间是干什么的啊= =

好了, 大概就是这些,文中大部分都是写的都是自己的理解, 并不是官方解释, 如有错误请大家指出 谢谢了~~





没图你说个图 发表于 2016-9-27 23:16

程序运行当然要申请空间

展鸿 发表于 2016-9-27 23:29

stdenvp设置了一个全局二维数组,用来保存环境变量值。

StriveMario 发表于 2016-9-27 23:30

展鸿 发表于 2016-9-27 23:29
stdenvp设置了一个全局二维数组,用来保存环境变量值。

{:1_893:}谢谢...学习了

Hymn 发表于 2016-9-28 00:57

好东西,感谢楼主。我要学习学习{:301_1003:}

zhashia 发表于 2016-9-28 01:40

复杂啊,只知道用malloc不知道原理

MAXtoDEATH 发表于 2016-9-28 10:40

手持两把锟斤拷,口中疾呼烫烫烫
脚踏千朵屯屯屯,笑看万物锘锘锘

yeyulang 发表于 2016-9-28 17:35

虽然看不懂..不过努力学习!

caroot1996 发表于 2016-9-28 23:25

第一次看到malloc的原理,楼主666
页: [1]
查看完整版本: C语言malloc的内存在堆中存放与管理