内存管理相关知识点 及 malloc 与 free

来源:互联网 发布:ubuntu版qq下载 编辑:程序博客网 时间:2024/06/03 18:35

物理内存和虚拟内存


要理解内存在程序中是如何分配的,首先需要理解如何将内存从操作系统分配给程序。计算机上的每一个进程都认为自己可以访问所有的物理内存。显然,由于同时在运行多个程序,所以每个进程不可能拥有全部内存。实际上,这些进程使用的是 虚拟内存

只是作为一个例子,让我们假定您的程序正在访问地址为 629 的内存。不过,虚拟内存系统不需要将其存储在位置为 629 的 RAM中。实际上,它甚至可以不在 RAM 中 —— 如果物理 RAM 已经满了,它甚至可能已经被转移到硬盘上!由于这类地址不必反映内存所在的物理位置,所以它们被称为虚拟内存。操作系统维持着一个虚拟地址到物理地址的转换的表,以便计算机硬件可以正确地响应地址请求。并且,如果地址在硬盘上而不是在 RAM中,那么操作系统将暂时停止您的进程,将其他内存转存到硬盘中,从硬盘上加载被请求的内存,然后再重新启动您的进程。这样,每个进程都获得了自己可以使用的地址空间,可以访问比您物理上安装的内存更多的内存。

 

在 32-位 x86 系统上,每一个进程可以访问 4 GB 内存。现在,大部分人的系统上并没有 4 GB 内存,即使您将 swap 也算上, 每个进程所使用的内存也肯定少于 4 GB。因此,当加载一个进程时,它会得到一个取决于某个称为 系统中断点(system break)的特定地址的初始内存分配。该地址之后是未被映射的内存 —— 用于在 RAM 或者硬盘中没有分配相应物理位置的内存。因此,如果一个进程运行超出了它初始分配的内存,那么它必须请求操作系统“映射进来(map in)”更多的内存。(映射是一个表示一一对应关系的数学术语 —— 当内存的虚拟地址有一个对应的物理地址来存储内存内容时,该内存将被映射。)

 

内存管理基本技术之:块头

代码:

void myfree(void* p)
{
          void* pointer = (char*)p – sizeof(Header);
          return free(pointer);
}
复制内容到剪贴板
代码:

typedef unsigned long Header;
void* mymalloc (size_t size)
{
          void* mem = malloc(size + sizeof(Header));
          *((Header*)mem) = size;
          return (char*)mem + sizeof(Header);
}

这样可以计算free内存的大小


深入理解malloc 与 free

在malloc时带了size, free的时候却没有带,那么它回收的时候,怎么知道它的大小呢?

 在malloc的时候, 会分配一个管理节点.

   blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;  // dbgheap.c  389行

   其中_CrtMemBlockHeader 是一个32个字节的结构体.

  nSize  为你malloc时带的大小.

  nNoMansLandSize 的大小为4.

 那么blockSize 整个空间的结构如下:

 

 pBlockHeaderNext  pBlockHeaderPrev  szFileName nLinenSize  nBlockUse lRequest gap real_data end   

其中 real_data 为nSize大小的实际有效的存储空间, gap和end 为实际存储空间的栅栏,固定为0xFD,

界定在存储空间的一头一尾, 在回收的时候,会检查实际存储空间的一头一尾是否为0xFD,

如果不是, 可能该空间被写越界了, 就不能正常回收了.

 blockSize 空间的初始化代码如下:

 pHead->pBlockHeaderNext = _pFirstBlock;  // dbgheap.c  431行
 pHead->pBlockHeaderPrev = NULL;
 pHead->szFileName = (char *)szFileName;
 pHead->nLine = nLine;
 pHead->nDataSize = nSize;   // 记录 malloc的大小
 pHead->nBlockUse = nBlockUse;
 pHead->lRequest = lRequest;

  /* link blocks together */
  _pFirstBlock = pHead;

  /* fill in gap before and after real block */
  memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize); // 四个字节,固定为0xFD
  memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize); // 四个字节,固定为0xFD

  /* fill data with silly value (but non-zero) */
  memset((void *)pbData(pHead), _bCleanLandFill, nSize); // 初始化malloc空间, 设为0xCD

 

static unsigned char _bNoMansLandFill = 0xFD;   /* fill no-man's land with this */
static unsigned char _bDeadLandFill   = 0xDD;   /* fill free objects with this */
static unsigned char _bCleanLandFill  = 0xCD;   /* fill new objects with this */
static unsigned char _bAlignLandFill  = 0xBD;   /* fill no-man's land for aligned routines */

 

在VC2003下测试获得分配空间的大小:

#include <stdio.h>

int get_malloc_size(void * buff)
{
 int size = 0;
 unsigned char *p = (unsigned char*)buff - 16;
 size = *p++;
 size |= *p++ << 8;
 size |= *p++ << 16;
 size |= *p++ << 24;
 return size;
}

int main(int argc, char *argv[])

 unsigned char *buff;

 int size = 0;

 buff = (unsigned char *)malloc(1024);

 size = get_malloc_size(buff); // 获得刚刚分配的空间大小
 free(buff);

 return 0;
}

原创粉丝点击