欢迎您访问我爱IT技术网,今天小编为你分享的编程技术是:【让.Net 应用程序突破2G的内存访问限制】,下面是详细的分享!
让.Net 应用程序突破2G的内存访问限制
32位Windows操作系统下单个进程的用户模式内存访问的限制是2G,如果在boot.ini中设置了/3G开关,则最大为3G,超过3G将无法访问。由于Hubble.net 项目是一个数据库系统,必须要考虑使用大内存缓存数据的问题,于是最近对这个问题进行了一些研究。其实这块的技术是现成的,32位操作系统下只有通过AWE的方式来扩展内存。这块的文章也很多,但很少有.net 下如何使用的实例,我做了一个类似MemoryStream的封装,可以让.Net程序员轻松操作AWE内存,从而使其程序轻松突破2G内存的限制。
在开始这篇文章之前,我们还是先来了解一下AWE.
AWE (Address Windowing Extensions)是 Windows 的内存管理功能的一组扩展,它使应用程序能够使用的内存量超过通过标准 32 位寻址可使用的 2-3 GB 内存。AWE 允许应用程序获取物理内存,然后将非分页内存的视图动态映射到 32 位地址空间。虽然 32 位地址空间限制为 4 GB,但是非分页内存却可以远远大于 4 GB。这使需要大量内存的应用程序(如大型数据库系统)能使用的内存量远远大于 32 位地址空间所支持的内存量。

如上图所示AWE 实际上就是将用户模式下的32位内存地址映射到用户需要访问的物理内存上去。不同操作系统运行被映射的物理内存大小是不一样的。
Vista, XP 和 Windows 2003 标准版 最多可以映射 4G 内存。
Windows 2003 企业版的限制是32G (要使用超过4G的内存必须打开 /PAE 开关)
Windows 2003 数据中心版本限制是64G (要使用超过4G的内存必须打开 /PAE 开关)
由于被映射的物理内存为不分页内存,无法进行页保护,为了保证内存使用的安全,防止其他进程越界访问,AWE 在映射这些内存之前必须将这些内存锁定,即只有锁定这块内存的进程可以访问这块内存,其它进程无法访问。这里就产生了一个有趣的现象,我们可以在windows 下像实时操作系统那样操作物理内存,而不用担心操作系统进行页交换时对系统实时性的影响。虽然不采用AWE,也可以通过VirtualLock API函数来锁定物理内存,但这个函数在一个进程中最多可以锁定30个页面,以一个页大小4096来计算,最多可以锁定30*4094字节的内存。当然这是默认设置,你也可以通过调整工作 WorkingSet 来调整。看来AWE对于那些实时性比较高的应用,比如游戏,动画,通讯等还确实是一个福音。
由于需要锁定物理内存,所以运行AWE功能的程序,必须要具备锁定内存的权限,系统管理员帐号是没有这个权限的,只有 System帐号有这个权限。当然你也可以在本地安全设置中指定某个帐号拥有这个权限。方法如下:
gpedit.msc ->Windows Settings->Security Settings->Local Policies->User Rights Assignment->Lock pages in memory
谈完锁定内存的问题,我们再看看上面那个图,我们会发现虽然AWE允许访问最多64G的内存,但这64G内存是被AWE映射到一个32位的用户模式下的内存地址中去的,也就是说通常情况下,我们最多可以同时访问64G内存中的2G内存 (如果配置了/3G开关,可以同时访问最多16G内存中的3G内存),如果要访问整个64G的内存,我们需要将一些不访问的内存取消映射,这样可以空出足够的用户模式下的虚拟内存地址来访问我们需要访问的内存。因此我封装的类中添加了Map和UnMap两个方法,让调用者可以根据实际情况来决定映射和去映射。2G的32位虚拟内存地址对于我们来是是如此的宝贵,调用者在贪婪的消耗大量内存时一定要注意节约这个资源。
谈完这些东西,下面让我们结合代码来看看在.Net 下如何来操作AWE 内存吧。
为了方便.Net 程序员访问AWE内存,我封装了一个AweStream类,这个类继承自Stream类。.Net程序员可以像操作普通的MemoryStream流那样操作AWE内存。同时我还为那些对效率要求非常苛刻的调用者提供了一个通过指针访问AWE内存的方法。
调用示例如下:注意必须在构造函数中指明申请的AWE内存的大小。
|
以下为引用的内容: byte[] inputBuffer=new byte[1024]; Stopwatch stopWatch=new Stopwatch(); using (AweStream.AweStream aweStream=new AweStream.AweStream(1024 * 1024 * 100)) //Copy one bytes stopWatch.Stop(); Console.WriteLine(stopWatch.ElapsedMilliseconds); aweStream.Position=0; for (int i=0; i < 1024 * 100; i++) stopWatch.Stop(); Console.WriteLine(stopWatch.ElapsedMilliseconds); //UnMap |
我在 6G内存 windows 2003 企业版的环境中做了测试,申请内存到5G以上没有任何问题。
下面再看看如何来申请AWE内存
下面的AweStream构造函数完成了对AWE内存的申请过程。
整个申请过程分为下面几步
以下为引用的内容:
public AweStream(UInt32 capacity)
{
unsafe
{
// Enable the privilege of lock memory.
lock (_SetLockPagesPrivilegeLockObj)
{
if (!_SetLockPagesPrivilegeOk)
{
LoggedSetLockPagesPrivilege.SetLockPagesPrivilege(System.Diagnostics.Process.GetCurrentProcess(), true);
_SetLockPagesPrivilegeOk=true;
}
}
General.SYSTEM_INFO sysInfo;
General.GetSystemInfo(out sysInfo); // fill the system information structure
_PageSize=sysInfo.dwPageSize;
if ((capacity % _PageSize) !=0)
{
_NumberOfPages=capacity / _PageSize + 1;
}
else
{
_NumberOfPages=capacity / _PageSize;
}
_PFNArraySize=(UInt32)(_NumberOfPages * sizeof(UInt64*)); // memory to request for PFN array
_PFNArray=Marshal.AllocHGlobal((int)_PFNArraySize);
UInt32 numberOfPagesInitial=_NumberOfPages;
if (!AweApi.AllocateUserPhysicalPages(System.Diagnostics.Process.GetCurrentProcess().Handle,
ref _NumberOfPages, _PFNArray))
{
Dispose();
throw new AweStreamException("Cannot allocate physical pages", AweStreamException.Reason.CannotAllocatePhysicalPages);
}
_AweAllocated=true;
if (numberOfPagesInitial !=_NumberOfPages)
{
Dispose();
throw new AweStreamException(string.Format("Allocated only {0} pages.", _NumberOfPages),
AweStreamException.Reason.AweMemoryNotEnough);
}
_Capacity=_PageSize * _NumberOfPages;
}
}
以下为引用的内容:
public void Map(bool readOnly)
{
unsafe
{
if (IsMapped)
{
return;
}
if (readOnly)
{
_VirtualAddress=AweApi.VirtualAlloc(null, Capacity, AweApi.MEM_RESERVE | AweApi.MEM_PHYSICAL,
AweApi.PAGE_READONLY);
}
else
{
_VirtualAddress=AweApi.VirtualAlloc(null, Capacity, AweApi.MEM_RESERVE | AweApi.MEM_PHYSICAL,
AweApi.PAGE_READWRITE);
}
if (_VirtualAddress==null)
{
throw new AweStreamException("Cannot reserve memory.", AweStreamException.Reason.CannotReserveMemory);
}
if (!AweApi.MapUserPhysicalPages(_VirtualAddress, _NumberOfPages, _PFNArray))
{
AweApi.VirtualFree(_VirtualAddress, Capacity, AweApi.MEM_RELEASE);
_VirtualAddress=null;
throw new AweStreamException(string.Format("MapUserPhysicalPages failed ({0})", General.GetLastError()),
AweStreamException.Reason.MapUserPhysicalPagesFail);
}
_CanWrite=!readOnly;
}
}
以上所分享的是关于让.Net 应用程序突破2G的内存访问限制,下面是编辑为你推荐的有价值的用户互动:
相关问题:32位win7,已破解内存,现在toad for db2每次到了1...
答:Net 应用程序如何在32位操作系统下申请超过2G的内存 2008 年我写过一篇博客叫 《让.Net 应用程序突破2G的内存访问限制》这篇博客主要讲述了如何在32位操作系统下利用AWE 扩展访问超过2G的内存。AWE方式虽然可以访问超过2G的内存,但其本身也有一... >>详细
相关问题:32位win7系统下,怎么让ae突破2g的限制,我的电脑...
答:1、本文适合64位的Windows7、Vista系统用户。2、本文是让32位应用程序能彻底使用4GB以上的虚拟内存,是的,看好了,虚拟内存。3、本文提到的4GB Patch是对选中的应用程序进行“破解”,而不是一劳永逸的对系统破解。4、这个和之前我们介绍过的系统... >>详细
相关问题:怎么让32位系统完全利用4G内存
答:其实,Win7以上的32位的系统,可以识别到你安装内存的总量,超过4G的内存也能识别,但由于32位CPU的访问能力限制(其实能解决,但微软故意不解决),只能利用3.25G的内存,剩下的内存完全浪费。 网上所谓的内存补丁,其实只能把浪费的那些内存模拟... >>详细
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
