C技巧(内存分配:更换策略,不要为难内存)

C技巧(内存分配:更换策略,不要为难内存),第1张

C技巧(内存分配:更换策略,不要为难内存),第2张

在32位计算机上(64位也一样,但是空要大得多),一个进程可以分配4GB的虚拟内存。当然,2GB的虚拟内存给了内核,剩下的2GB一部分分配给代码段和数据段。最后,剩下的就是我们程序员的事了。这样,一个应用程序强行读取2 GB左右的数据就是一个极限。
然而,事实并非如此。只要使用了虚拟内存技术,有时候还是可以读取的。
先说windows虚拟内存的想法:
虚拟内存就是实际上可能没有实际内存的内存。如果CPU要访问一个虚拟内存,哪个操作系统首先要判断这个虚拟内存是否有实际内存。如果是这样,你就可以大方的读取甚至写入数据。
但如果没有,操作系统必须在真实内存中找到位置,并与要读取的虚拟内存建立映射关系,这样才能读取。当然,如果找不到这么多的实内存,可以把一些不用的实内存放在下一级硬盘临时空室,腾出空间给空,然后建立与虚拟内存的映射关系。
当然,比如你想读取2GB的数据,反正在1 GB的内存里找不到足够的空来建立映射关系。当然,我们不可能一次读取2GB的数据,所以我们引入了“页面”的概念,即每次虚拟内存碰到真实内存时,都按照页面大小进行映射。这个页面大小,和CPU有关,在X86上一般是4KB。
说到这里,读取大数据的想法就出来了。我们可以先分配虚拟内存,然后在读取或写入一些数据时再分配实际内存。由于这些都是在内存级别操作的,所以效率远远高于读写数据时从硬盘中取出来的效率。
windows API让我们很容易做到这一点。
VirtualAlloc,可应用于虚拟内存或实际映射到真实内存的内存。我们可以先申请虚拟内存,真正要在某个地方读取数据的时候再申请真实内存(建立映射关系)。
详情请见MSDN。下面是一个示例代码:
# include
# include
struct sheet//我们要读取的数据结构
{
int nSize;
BOOL b visible;
char big[1024 * 15];
STD::string strText;
};
int main()
{
SYSTEM _ INFO si;
getsystem info(& si);
DWORD dw pagesize = si . dw pagesize;//获取CPU读取的页面大小
//将页面单位转换为字节(原来页面单位是KB,但是我们的数据结构是按字节计算的)
dword dwpageasbyte = dw pagesize * 1024;
//下面的dw occupate占用空一个数据结构。由于实际内存是按页分配的,所以空的并集是page
dword dw mod = sizeof(sheet)% dwpageasbyte;的整数倍。
DWORD dw occuit = 0;
if (dwMod!= 0)
{
dw occuit =(sizeof(Sheet)/dwPageAsByte)* dwPageAsByte+dwPageAsByte;
}
else
{
dw occupy = sizeof(Sheet);
}
/申请虚拟内存,MEM_RESERVE表示不会与实际内存建立映射关系
lpvoid lpbase addr = virtualalloc(null,dwoccupancy * 50,mem _ reserve,page _ read write);
if(lpbase addr = = NULL)
{
return 1;
}
_ _ try
{
DWORD dwIndex = 0;
//在下面输入要连续读取的数据。如果该数据尚未建立实际的内存映射关系,则建立
while(true)
{
STD::cout > dwindex;
//根据输入的索引,计算要读取的数据结构的地址。注意也是由page
lpvoid lpsheetaddr =(lpvoid)((dword)lpbase addr+(dwindex-1)* dw occupy)分配的;
MEMORY _ BASIC _ INFORMATION mbi;
memset(&mbi,0,sizeof(mbi));
//查询内存状态
if(虚拟查询(lpsheetaddr,&mbi,Zeof(MBI))= = Sizeof(MBI))
{
If(MBI。state = = MEM _ reserve)//属于保留状态
{
/建立与实际内存的映射关系[/br/LPVOID lpAlloc = VirtualAlloc(lpSheetAddr,dwOccupy,MEM_COMMIT,PAGE _ read write);
if(lpAlloc = = NULL)
{
STD::cout strText = " hello world ";
p sheet-> b visible = TRUE;
}
}
_ _ exception(exception _ execute _ handler)
{
}
free mem
virtual free(lpbase addr,0,mem
}
当然还有一个影响效率的VirtualQuery函数,事实上,异常处理可以用来提高效率。以后再说吧。
您还可以添加删除代码。当不再使用某些数据时,可以将虚拟内存状态重置为MEM保留,这样可以节省实际内存。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C技巧(内存分配:更换策略,不要为难内存)

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情