您的位置:首页 > 其它

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

2010-07-06 18:06 267 查看
物理内存和虚拟内存



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


只是作为一个例子,让我们假定您的程序正在访问地址为 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 szFileNamenLinenSize
nBlockUselRequestgap
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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: