首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
85 阅读
2
nvim番外之将配置的插件管理器更新为lazy
69 阅读
3
2018总结与2019规划
55 阅读
4
PDF标准详解(五)——图形状态
36 阅读
5
为 MariaDB 配置远程访问权限
32 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
emacs
linux
文本编辑器
Java
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
是金子总会发光的,可你我都是老铁
累计撰写
311
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
1
篇与
的结果
2016-07-21
windows 堆管理
windows堆管理是建立在虚拟内存管理的基础之上的,每个进程都有独立的4GB的虚拟地址空间,其中有2GB的属于用户区,保存的是用户程序的数据和代码,而系统在装载程序时会将这部分内存划分为4个段从低地址到高地址依次为静态存储区,代码段,堆段和栈段,其中堆的生长方向是从低地址到高地址,而栈的生长方向是从高地址到低地址。程序申请堆内存时,系统会在虚拟内存的基础上分配一段内存,然后记录下来这块的大小和首地址,并且在对应内存块的首尾位置各有相应的数据结构,所以在堆内存上如果发生缓冲区溢出的话,会造成程序崩溃,这部分没有硬件支持,所有管理算法都有开发者自己设计实现。堆内存管理的函数主要有HeapCreate、HeapAlloc、HeapFree、HeapRealloc、HeapDestroy、HeapWalk、HeapLock、HeapUnLock。下面主要通过一些具体的操作来说明这些函数的用法。堆内存的分配与释放堆内存的分配主要用到函数HeapAlloc,下面是这个函数的原型:LPVOID HeapAlloc( HANDLE hHeap, //堆句柄,表示在哪个堆上分配内存 DWORD dwFlags, //分配的内存的相关标志 DWORD dwBytes //大小 );堆句柄可以使用进程默认堆也可以使用用户自定义的堆,自定义堆使用函数HeapCreate,函数返回堆的句柄,使用GetProcessHeap可以获取系统默认堆,返回的也是一个堆句柄。分配内存的相关标志有这样几个值:HEAP_NO_SERIALIZE:这个表示对堆内存不进行线程并发控制,由于系统默认会进行堆的并发控制,防止多个线程同时分配到了同一个堆内存,如果程序是单线程程序则可以添加这个选项,适当提高程序运行效率。HEAP_ZERO_MEMORY:这个标志表示在分配内存的时候同时将这块内存清零。HeapCreate函数的原型如下:HANDLE HeapCreate( DWORD flOptions, //堆的相关属性 DWORD dwInitialSize, //堆初始大小 DWORD dwMaximumSize //堆所占内存的最大值 );flOptions的取值如下:HEAP_NO_SERIALIZE:取消并发控制HEAP_SHARED_READONLY:其他进程可以以只读属性访问这个堆dwInitialSize, dwMaximumSize这两个值如果都是0,那么堆内存的初始大小由系统分配,并且堆没有上限,会根据具体的需求而增长。下面是使用的例子: //在系统默认堆中分配内存 srand((unsigned int)time(NULL)); HANDLE hHeap = GetProcessHeap(); int nCount = 1000; float *pfArray = (float *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, nCount * sizeof(float)); for (int i = 0; i < nCount; i++) { pfArray[i] = 1.0f * rand(); } HeapFree(hHeap, HEAP_NO_SERIALIZE, pfArray); //在自定义堆中分配内存 hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0, 0); pfArray = (float *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, nCount * sizeof(float)); for (int i = 0; i < nCount; i++) { pfArray[i] = 1.0f * rand(); } HeapFree(hHeap, HEAP_NO_SERIALIZE, pfArray); HeapDestroy(hHeap);遍历进程中所有堆的信息:便利堆的信息主要用到函数HeapWalk,该函数的原型如下:BOOL WINAPI HeapWalk( __in HANDLE hHeap,//堆的句柄 __in_out LPPROCESS_HEAP_ENTRY lpEntry//返回堆内存的相关信息 );下面是PROCESS_HEAP_ENTRY的原型:typedef struct _PROCESS_HEAP_ENTRY { PVOID lpData; DWORD cbData; BYTE cbOverhead; BYTE iRegionIndex; WORD wFlags; union { struct { HANDLE hMem; DWORD dwReserved[3]; } Block; struct { DWORD dwCommittedSize; DWORD dwUnCommittedSize; LPVOID lpFirstBlock; LPVOID lpLastBlock; } Region; }; } PROCESS_HEAP_ENTRY, *LPPROCESS_HEAP_ENTRY;这个结构中的公用体具体使用哪个与wFlags相关,下面是这些值得具体含义:wFlags堆入口含义lpDatacbDatacbOverhead块前堆数据结构大小iRegionIndexBlockRegionPROCESS_HEAP_ENTRY_BUSY被分配的内存块首地址内存块大小内存块前堆数据结构所在区域索引无意义无意义PROCESS_HEAP_ENTRY_DDESHAREDDE共享内存块首地址内存块大小内存块前堆数据结构所在区域索引无意义无意义PROCESS_HEAP_ENTRY_MOVEABLE可移动的内存块(兼容GlobalAllocLocalAlloc)首地址(可移动内存句柄的首地址)内存块大小内存块前堆数据结构所在区域索引与PROCESS_HEAP_ENTRY_BUSY标志一同指定可移动内存句柄值无意义PROCESS_HEAP_REGION已提交的堆虚拟内存区域区域开始地址区域大小区域前堆数据结构区域索引无意义虚拟内存区域详细信息PROCESS_HEAP_UNCOMMITTED_RANGE未提交的堆虚拟内存区域区域开始地址区域大小区域前堆数据结构区域索引无意义无意义下面是时遍历堆内存的例子: PHANDLE pHeaps = NULL; //当传入的参数为0和NULL时,函数返回进程中堆的个数 int nCount = GetProcessHeaps(0, NULL); pHeaps = new HANDLE[nCount]; //获取进程所有堆句柄 GetProcessHeaps(nCount, pHeaps); PROCESS_HEAP_ENTRY phe = {0}; for (int i = 0; i < nCount; i++) { cout << "Heap handle: 0x" << pHeaps[i] << '\n'; //在读取堆中的相关信息时需要将堆内存锁定,防止程序向堆中写入数据 HeapLock(pHeaps[i]); HeapWalk(pHeaps[i], &phe); //输出堆信息 cout << "\tSize: " << phe.cbData << " - Overhead: " << static_cast<DWORD>(phe.cbOverhead) << '\n'; cout << "\tBlock is a"; if(phe.wFlags & PROCESS_HEAP_REGION) { cout << " VMem region:\n"; cout << "\tCommitted size: " << phe.Region.dwCommittedSize << '\n'; cout << "\tUncomitted size: " << phe.Region.dwUnCommittedSize << '\n'; cout << "\tFirst block: 0x" << phe.Region.lpFirstBlock << '\n'; cout << "\tLast block: 0x" << phe.Region.lpLastBlock << '\n'; } else { if(phe.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) { cout << "n uncommitted range\n"; } else if(phe.wFlags & PROCESS_HEAP_ENTRY_BUSY) { cout << "n Allocated range: Region index - " << static_cast<unsigned>(phe.iRegionIndex) << '\n'; if(phe.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) { cout << "\tMovable: Handle is 0x" << phe.Block.hMem << '\n'; } else if(phe.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) { cout << "\tDDE Sharable\n"; } } else cout << " block, no other flags specified\n"; } cout << std::endl; HeapUnlock(pHeaps[i]); ZeroMemory(&phe, sizeof(PROCESS_HEAP_ENTRY)); } delete[] pHeaps;另外堆还有其他操作,比如使用HeapSize获取分配的内存大小,使用HeapValidate可以校验一个对内存的完整性,从而提早发现”野指针”等等。
2016年07月21日
4 阅读
0 评论
0 点赞