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 一样需要锁定内存页的权限。

代码及配图

图中表示了下面代码对内存操作的步骤: 2016-04-13_225214

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#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;
}