WIN32内存管理问题

lyserver 2008-04-09 08:03:03
这段时间由于一个项目中需要大量申请、初始化、调整和释放内存,我知道如果使用固定内存块,可加快申请速度并可将内存块初始化0,奇怪的是,如果使用移动内存块,内存块初始化为0的操作往往会被忽略,是不是由于申请移动内存块时,内存块指针未锁定,所以无法进行初始化为0的操作?比如:
hMem=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE,sizeof(myStuct)*1000);
//GlobalAlloc函数中的GMEM_ZEROINIT标志未起作用,除非使用memset(hMem,0,sizeof(myStruct)*1000)显式初始化内存块为0。
hMem=GlobalReAlloc(hMem,sizeof(myStruct)*2000,GMEM_ZEROINIT|GMEM_MOVEABLE);
//由于使用GlobalReAlloc函数前需要GlobalUnlock,所以GMEM_ZEROINIT仍然没有起作用。

请教jiangsheng可不可以在申请移动内存块的同时进行内存块的初始化(即不使用memset,为了效率)?
另外一个问题,本来以为使用移动内存块可避免内存碎片化,可经过实践仍然会产生碎片而导致内存申请失败,请问如何有效避免内存碎片化?
...全文
175 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
cnzdgs 2008-04-10
  • 打赏
  • 举报
回复
给你看看我的测试代码,一个控制台程序。
	int Length = 0x1234567;
HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, Length*sizeof(DWORD));
if (h != NULL)
{
PDWORD p = (PDWORD)::GlobalLock(h);
if (p != NULL)
{
int i;
for (i=0; i<Length; i++)
{
if (p[i] != 0)
{
printf("Found at 0x%x!", i);
break;
}
}
if (i == Length)
{
printf("Not found.\n");
}
::GlobalUnlock(h);
}
::GlobalFree(h);
}
cnzdgs 2008-04-10
  • 打赏
  • 举报
回复
我是试过后没发现问题才回复的。
lyserver 2008-04-10
  • 打赏
  • 举报
回复
cnzdgs:
我是说当申请的是移动内存块时,GMEM_ZEROINIT不起作用,不信你试一试。

akirya:
谢谢你,我正打算基于内存影射文件做内存池(优点是可以预先分配大块内存,减小内存调整量,有效防止内存碎片,缺点是初始化结构数组太慢,打算单独起一个线程初始化内存块为0),因为项目最大内存量超过1G,而又要求可以顺畅地运行在256M环境中。不知有没有更好的办法,要求是尽量减少物理内存使用量、避免内存大量调整、防止内存碎片、同时加快系统响应速度。

zhoujianhei 2008-04-10
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 akirya 的回复:]
使用内存池,而不是每次使用均由api来分配内存.
[/Quote]
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 lyserver 的回复:]
根据1楼提示,我知道使用内存池效果要好一些,关键是项目所使用的内存可能远远大于物理内存。
[/Quote]

内存256.还有虚拟内存呢,你api能分配多少,内存池就能用多少.
zhoujianhei 2008-04-10
  • 打赏
  • 举报
回复
一曲肝肠断,天涯何处觅知音。
lyserver 2008-04-10
  • 打赏
  • 举报
回复
cnzdgs:
使用私有堆分配内存和使用默认堆分配一样影响内存(即都没有立即使用物理内存,而是使用了虚拟内存),而且在分配相同数量的内存时,由于私有堆要考虑页对齐,会造成一些浪费,如以下代码中,私有堆明显比默认堆占有的内存要多。
HANDLE hHeap = HeapCreate(HEAP_NO_SERIALIZE,200*1024*1024,0);
LPVOID lpMemory = HeapAlloc(hHeap,HEAP_NO_SERIALIZE|HEAP_ZERO_MEMORY,200*1024*1024);
MessageBox(NULL,"私有堆内存分配","",MB_OK);
HeapFree(hHeap,HEAP_NO_SERIALIZE,lpMemory);
HeapDestroy(hHeap);
lpMemory= GlobalAlloc(GPTR,200*1024*1024);
MessageBox(NULL,"默认堆内存分配","",MB_OK);
GlobalFree(lpMemory);
return 0;
不过私有堆确实能克服内存碎片的缺点。
cnzdgs 2008-04-10
  • 打赏
  • 举报
回复
堆分配内存不受物理内存影响,只与进程的用户地址空间有关,进程有2GB用户地址空间,一般用到1.5GB是没问题的。
cnzdgs 2008-04-10
  • 打赏
  • 举报
回复
移动内存可以理解为:先分配一块新内存,把原内存的数据复制过去,再把原内存释放。因为全局内存从开机到关机整个过程中一直在分配、释放,而没有机会清理,所以很容易产生碎片。
lyserver 2008-04-10
  • 打赏
  • 举报
回复
根据1楼提示,我知道使用内存池效果要好一些,关键是项目所使用的内存可能远远大于物理内存。
lyserver 2008-04-10
  • 打赏
  • 举报
回复
谢谢cndzgs:
原来是我的代码中有一处把锁定前的内存块句柄当作内存块指针使用了。
但为什么移动内存块也会产生碎片呢?
cnzdgs 2008-04-09
  • 打赏
  • 举报
回复
LZ是怎么确定GlobalAlloc没有清零的?有一点提醒一下,GlobalReAlloc只会把增加的内存清零。

全局内存通常是不使用,除非是在进程间传递数据,不过一般也不会分配大块的全局内存。使用全局内存,很容易造成内存碎片。另外,全局内存的分配、重分配、释放都比局部内存要慢。如无特殊需要,建议使用堆内存。
  • 打赏
  • 举报
回复
使用内存池,而不是每次使用均由api来分配内存.

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧