AWE (Address Windows Extension) 可以使用开启 PAE 后普通应用程序无法使用到的内存,这部分内存系统可能无法识别,但通过 AWE 则可以完美访问。操作 AWE 内存的具体步骤如下,大部分内容来自北风网视频教程。 1、开窗 VirtualAlloc MEM_PHYSICAL,明确告知系统,这段保留的空间未来将存放我自己申请的物理内存。 2、分配物理内存 AllocateUserPhysicalPages,按页面个数来分配,不是按字节分配的,最少一个页面 4K 的物理内存。 3、将申请好的物理内存映射到窗口中(相当于提交)MapUserPhysicalPages。 4、对已经提交的内存读写… 5、释放物理内存页面。
注意事项
1、打开 PAE 后并不是所有应用程序都可以访问大于 4GB 的内存,要访问需要通过 AWE 打开 PAE 高出 4GB 地址空间的内存,AWE 但不仅限于打开 PAE 后多出来的内存,当需要自己操作物理页面的时候,都可以用到它。(顺网无盘的产品利用系统未识别的内存做缓存就是这个原理) 2、使用 AWE 一样需要锁定内存页的权限。
代码及配图
图中表示了下面代码对内存操作的步骤:
代码语言:javascript复制#define _WIN32_WINNT 0x0502
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#define MEMORY_REQUESTED 1024 * 1024 * 1024 //1GB
BOOL LoggedSetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable);
void _cdecl main()
{
BOOL bResult; // generic Boolean value
ULONG_PTR NumberOfPages; // number of pages to request
ULONG_PTR NumberOfPagesInitial; // initial number of pages requested
ULONG_PTR *aPFNs1; // page info; holds opaque data
ULONG_PTR *aPFNs2; // page info; holds opaque data
PVOID lpMemReserved; // AWE window
SYSTEM_INFO sSysInfo; // useful system information
int PFNArraySize; // memory to request for PFN array
TCHAR* pszData;
TCHAR pszReadData[100];
MEMORYSTATUSEX ms = { sizeof(MEMORYSTATUSEX) };
GlobalMemoryStatusEx(&ms);
// LoggedSetLockPagesPrivilege(::GetCurrentProcess(),TRUE);
//1 "开窗"
lpMemReserved = VirtualAlloc(NULL, MEMORY_REQUESTED, MEM_RESERVE MEM_PHYSICAL, PAGE_READWRITE);
//计算需要的物理页面大小 以及物理页面需要的页表数组大小
GetSystemInfo(&sSysInfo); // fill the system information structure
NumberOfPages = (MEMORY_REQUESTED sSysInfo.dwPageSize - 1) / sSysInfo.dwPageSize;
PFNArraySize = NumberOfPages * sizeof(ULONG_PTR);
//2 准备物理页面的页表数组数据
aPFNs1 = (ULONG_PTR *)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
aPFNs2 = (ULONG_PTR *)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
NumberOfPagesInitial = NumberOfPages;
//3 分配物理页面
bResult = AllocateUserPhysicalPages(GetCurrentProcess(), &NumberOfPages, aPFNs1);
bResult = AllocateUserPhysicalPages(GetCurrentProcess(), &NumberOfPages, aPFNs2);
//4 映射第一个1GB到保留的空间中
bResult = MapUserPhysicalPages(lpMemReserved, NumberOfPages, aPFNs1);
pszData = (TCHAR*)lpMemReserved;
_tcscpy(pszData, _T("这是第一块物理内存"));
//5 映射第二个1GB到保留的空间中
bResult = MapUserPhysicalPages(lpMemReserved, NumberOfPages, aPFNs2);
_tcscpy(pszData, _T("这是第二块物理内存"));
//6 再映射回第一块内存,并读取开始部分
bResult = MapUserPhysicalPages(lpMemReserved, NumberOfPages, aPFNs1);
_tcscpy(pszReadData, pszData);
//7 取消映射
bResult = MapUserPhysicalPages(lpMemReserved, NumberOfPages, NULL);
//8 释放物理页面
bResult = FreeUserPhysicalPages(GetCurrentProcess(), &NumberOfPages, aPFNs1);
bResult = FreeUserPhysicalPages(GetCurrentProcess(), &NumberOfPages, aPFNs2);
//9 释放保留的"窗口"空间
bResult = VirtualFree(lpMemReserved, 0, MEM_RELEASE);
//10 释放页表数组
bResult = HeapFree(GetProcessHeap(), 0, aPFNs1);
bResult = HeapFree(GetProcessHeap(), 0, aPFNs2);
_tsystem(_T("PAUSE"));
}
/*****************************************************************
LoggedSetLockPagesPrivilege: a function to obtain or
release the privilege of locking physical pages.
Inputs:
HANDLE hProcess: Handle for the process for which the
privilege is needed
BOOL bEnable: Enable (TRUE) or disable?
Return value: TRUE indicates success, FALSE failure.
*****************************************************************/
BOOL
LoggedSetLockPagesPrivilege(HANDLE hProcess,
BOOL bEnable)
{
struct {
DWORD Count;
LUID_AND_ATTRIBUTES Privilege[1];
} Info;
HANDLE Token;
BOOL Result;
// Open the token.
Result = OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES,
&Token);
if (Result != TRUE)
{
printf("Cannot open process token.n");
return FALSE;
}
// Enable or disable?
Info.Count = 1;
if (bEnable)
{
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
Info.Privilege[0].Attributes = 0;
}
// Get the LUID.
Result = LookupPrivilegeValue(NULL,
SE_LOCK_MEMORY_NAME,
&(Info.Privilege[0].Luid));
if (Result != TRUE)
{
printf("Cannot get privilege for %s.n", SE_LOCK_MEMORY_NAME);
return FALSE;
}
// Adjust the privilege.
Result = AdjustTokenPrivileges(Token, FALSE,
(PTOKEN_PRIVILEGES)&Info,
0, NULL, NULL);
// Check the result.
if (Result != TRUE)
{
printf("Cannot adjust token privileges (%u)n", GetLastError());
return FALSE;
}
else
{
if (GetLastError() != ERROR_SUCCESS)
{
printf("Cannot enable the SE_LOCK_MEMORY_NAME privilege; ");
printf("please check the local policy.n");
return FALSE;
}
}
CloseHandle(Token);
return TRUE;
}