目录
核心分析器的优势在于它能够将堆内存解析为数百万个单独的内存块,这些内存块由堆内存管理器分配给应用程序。只有掌握了这些知识,Core Analyzer才能检查内存损坏并搜索对象引用。鼓励用户了解基本堆数据结构,以最大程度地利用该工具的好处,并在必要时开发自己的自定义内存管理器支持。
我将简要说明Linux / Windows / Mac OS系统运行时内存管理器使用的数据结构。它们是开源的或反向工程的。您可以在项目的源文件,Linux内核源代码或许多在线网站中找到更多详细信息。由于操作系统供应商可能会更改每个新版本的实现,因此此描述可能与您使用的描述不同。在下面的所有图中,阴影区域表示堆数据结构,空白区域表示用户空间。
1. Ptmalloc
这是Linux上GNU C库使用的内存管理器。图书馆的glibc有一个全球性的“结构malloc_state ”对象,名为main_arena ,这是所有托管堆内存的根源。
Arena是存储区域的逻辑集合,用各种彩色轮廓表示。竞技场可以一次满足一个内存请求。如果同时存在多个请求,则ptmalloc将使用其他场所同时满足这些请求。如果没有可用的竞技场,则会创建新的竞技场。堆是由用户存储块组成的单个连续存储区。竞技场随时可能有一个或多个竞技场。
主竞技场和动态创建的竞技场之间的区别在于它们如何从内核获取内存。主区域调用sbrk(),通常在可执行文件的数据部分之后立即开始。另一方面,动态竞技场使用具有固定大小(例如64MB )的mmap(),并确保起始地址也按大小的倍数对齐。如果第一个堆用完了,则将对新的具有固定大小的堆进行mmap-ed,该堆将链接到动态竞技场的堆数据“ strcut malloc_state ”。
如果用户的请求超出了可以动态更改的阈值(例如128KB),则ptmalloc在释放时会调用mmap()来分配内存和munmap()。此类存储块不由任何堆数据链接。
堆上的每个内存块都由“ struct malloc_chunk ”边界标记管理。我们可以轻松地将堆作为链接列表遍历,每个标签作为到下一个内存块的偏移量。
struct malloc_chunk {
INTERNAL_SIZE_T prev_size;
INTERNAL_SIZE_T大小;
struct malloc_chunk * fd;
struct malloc_chunk * bk;
};
根据某个块及其上一个和下一个块是空闲的还是正在使用的,该结构的某些数据字段未使用,可能是用户空间的一部分。阴影区域中的数据是堆数据,属于ptmalloc。如果被应用程序覆盖,则是典型的堆数据损坏。
2. Windows内存管理器
为了遍历Windows上的内存堆,我们从全局对象peb (进程环境块)开始。它的数据成员“ ProcessHeaps ”指向“ struct _HEAP ”的指针数组,该数组以NULL指针终止。堆保留段列表。
段是一块连续的内存空间,由“ struct _HEAP_SEGMENT ”描述。它具有指向该段中第一个和最后一个存储块的指针。该段中还有一些未提交的内存范围,必要时将使这些范围可用。每个内存块前面都有一个“ struct _HEAP_ENTRY ”,该信息由该块的用户空间大小,填充,状态,加密字节等信息组成。在调试模式下,在用户空间之前添加“ struct _CrtMemBlockHeader ”。
3. Mac OS内存管理器
Mac OS上的内存管理器有两个全局变量位于堆数据结构的顶部:“ malloc_zones ”和“ malloc_num_zones ”。前者指向“ struct szone_t ”数组,而后者则指向该数组的大小。与glibc的Ptmalloc相比,zone等同于Mac OS上的竞技场,而region与堆相同。创建多个区域以同时服务多个线程。
像大多数内存管理器一样,根据内存请求的大小采用不同的算法。如果内存请求大小不大于31 * TINY_QUANTUM或496字节,则使用微小区域。如果大小等于或大于15KB,则使用大区域。否则,将选择小区域来满足请求。它们的堆数据结构如下所示。与Ptmalloc不同,每个内存块都没有附加标签。相反,每个区域都有一个位图,用于标记该区域中相应块的状态。
http://core-analyzer.sourceforge.net/index_files/Page335.html
4.推荐阅读
《TCMalloc:线程缓存Malloc以及tcmalloc与ptmalloc性能对比》