b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

为什么32位程序只能使用最大2GB内存?(图)

电脑杂谈  发布时间:2021-05-29 18:05:20  来源:网络整理

32 位应用程序如何使用超过 2GB 的内存?

无论是在 32 位 Windows 还是 64 位 Windows 中,32 位应用程序最多只能使用 2GB 的内存,这是我们习惯的常见设置。但实际上,Windows 为我们提供了一些方法来打破这种设置,让程序使用超过 2GB 的内存。

为什么 32 位程序最多只能使用 2GB 内存?

32 位寻址空间大小只有 4GB,因此 32 位应用程序(进程)最多只能使用 4GB 内存。但是,除了应用程序本身使用的内存外,操作系统内核还需要使用它。应用程序使用的内存空间分为用户空间和内核空间。每个32位程序的用户空间可以独占前2GB空间(指针值为正数),内核空间由所有进程共享2GB空间(指针值为负数)。因此,32位应用程序实际可以访问的内存地址空间最多只有2GB。

让 32 位程序使用超过 2GB 内存的两种方法

编辑器

这是Visual Studio 2017采用的方法,我们需要用到两个工具——editbin和dumpbin。前者用于编辑我们编译和生成的程序,以便头信息声明它支持超过2GB的内存,后者用于检查程序的头信息以验证我们是否已对其进行更改。

编辑程序以声明它支持超过 2GB 内存的命令是:

editbin /largeaddressaware xxx.exe

其中xxx.exe就是我们要修改的程序。您可以使用相对路径或绝对路径(如果路径中有空格,请记住加上引号)。

验证这个程序是否被改变的命令是:

dumpbin /headers xxx.exe | more

同理,xxx.exe就是我们刚才修改要检查的程序。您可以使用相对路径或绝对路径。

使用dumpbin查看我们编辑editbin前后的程序头信息,得到如下两张图:

32位系统设置最大内存

32位系统设置最大内存

请注意,FILE HEADER VALUES 块的倒数第二行有更多的应用程序可以处理大 (>2GB) 地址。

如果没找到,那肯定是你的命令执行出错了。检查!最常见的错误是执行后发现没有这样的命令。是的,editbin 命令从何而来?您可以在开始菜单的 Visual Studio 文件夹中找到 VS 2017 的开发人员命令提示符。运行此启动的命令行包含 editbin 和 dumpbin。

32位系统设置最大内存

如果希望在编译 Visual Studio 时能够自动调用此工具,请参考:LargeAddressAware Visual Studio 2015 C#。

编译到 AnyCPU(首选 32 位)

这是本文比较推荐的方法,也是最简单的方法。方法是打开入口程序集的属性页,选择“Target Platform”为“AnyCPU”,然后勾选“Prefer 32-bit”。应该注意的是,这种生成方法仅在.Net Framework 4. 5及更高版本中可用。

关于 AnyCPU (Prefer 32-bit) 和 x86 生成方式的区别,请参见:Visual Studio 2012 中“Prefer 32-bit”设置的目的是什么,它实际上是如何工作的?。

语句支持2GB以上内存后可以使用多少内存?

对于 32 位操作系统,程序仍然只能使用 2GB 内存,除非打开 /3GB 开关,请参阅:/3GB 了解详情。打开后,应用程序的用户态可以使用3GB内存,而内核态只能使用1GB内存。微软认为,是否开启/3GB开关是电脑设备开发者需要做的事情,开发者也需要在开启后测试驱动的性能和稳定性。

对于64位操作系统,Windows将慷慨地为此类程序贡献所有4GB的空间,因为系统本身已经具有更多可用的内存寻址空间,因此无需使用32位应用程序抢占寻址空间。 .

AWE(地址窗口扩展)

AWE 是对 Windows 内存管理功能的一组扩展。它允许应用程序获取物理内存,然后将非分页内存的视图动态映射到 32 位地址空间。尽管 32 位地址空间限制为 4GB,但非分页内存可以远大于 4GB。这允许需要大量内存的应用程序(例如大型系统)使用比 32 位地址空间支持的内存量大得多的内存量。

为了使用大容量内存,除了使用AWE之外,还有一件不能少的东西,那就是PAE(Physical Address Extension)。 PAE 是基于 x86 的服务器的一项功能,它使运行 Windows Server 2003 企业版和 Windows Server 2003 数据中心版的计算机能够支持超过 4 GB 的物理内存。物理地址扩展 (PAE) 允许最多 64 GB 的物理内存用作常规 4 KB 页面,并将内核可用于扩展物理内存地址的位数从 32 扩展到 36。

一般情况下,Windows系统的PAE不会生效。只有开启PAE,windows系统才能识别4G以上的内存。在使用boot.int的系统中,要启动PAE,必须将/ PAE选项添加到boot.ini中。在Windows Vista 和Windows7 中,必须同时修改内核文件和设置BCD 启动项。对于Vista和Win7系统,可以使用Ready For 4GB软件直接完成此项操作。具体方法见Ready For 4GB软件说明。以下是打开了 /PAE 选项的 boot.ini 文件示例:

32位系统怎么换64位设置_32位系统设置最大内存_32位win7系统无法使用4g内存

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)WINDOWS="Windows Server 2003, Enterprise" /fastdetect /PAE

本文将以Windows 7 Ultimate为例,介绍如何使用AWE来实现在打开PAE时在程序中使用超过2G内存的目的。下图显示了PAE开启和未开启时系统识别的内存容量差异。

32位系统设置最大内存

启用 PAE

32位系统设置最大内存

关闭 PAE

如果不开启PAE,系统只能识别3G内存,最多0.5G不到,所以即使你用AWE,因为系统和其他应用已经占用了部分内存,剩下的内存可能只是2G多一点,没有太大的改进。只有当系统识别出超过4G的内存时,AWE才能真正发挥作用。

我们来看看windows中给出的AWE相关的API函数。它们都在 winbase.h 中定义。

#if (_WIN32_WINNT >= 0x0500)
//
// Very Large Memory API Subset
//
WINBASEAPI
BOOL
WINAPI
AllocateUserPhysicalPages(
    __in    HANDLE hProcess,
    __inout PULONG_PTR NumberOfPages,
    __out_ecount_part(*NumberOfPages, *NumberOfPages) PULONG_PTR PageArray
    );
WINBASEAPI
BOOL
WINAPI
FreeUserPhysicalPages(
    __in    HANDLE hProcess,
    __inout PULONG_PTR NumberOfPages,
    __in_ecount(*NumberOfPages) PULONG_PTR PageArray
    );
WINBASEAPI
BOOL
WINAPI
MapUserPhysicalPages(
    __in PVOID VirtualAddress,
    __in ULONG_PTR NumberOfPages,
    __in_ecount_opt(NumberOfPages) PULONG_PTR PageArray
    );
//...
#endif

从winbase.h中的定义可以看出,AWE只能在你的系统版本大于等于0x0500时使用。

各版本的_WIN32_WINNT值如下表所示。 AWE 不能用于 Windows 2000 以下的版本。

最低系统要求

_WIN32_WINNT 和WINVER 的最小值

Windows7

0x0601

Windows Server2008

0x0600

Windows Vista

0x0600

Windows Server2003 SP1,WindowsXP SP2

0x0502

Windows Server2003、WindowsXP

0x0501

Windows2000

0x0500

如果您的系统版本符合要求,但是编译器在编译添加AWE API的代码时出现错误,您可以在程序头文件中添加如下代码。

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif	

下面简单介绍一下各个API的功能。

BOOL WINAPI AllocateUserPhysicalPages(	//分配物理内存页,用于后面AWE的内存映射
  __in     HANDLE hProcess,		//指定可以使用此函数分配的内存页的进程
  __inout  PULONG_PTR NumberOfPages,	//分配的内存页数,页的大小由系统决定
  __out    PULONG_PTR UserPfnArray	//指向存储分配内存页帧成员的数组的指针
);
BOOL WINAPI FreeUserPhysicalPages(	//释放AllocateUserPhysicalPages函数分配的内存
  __in     HANDLE hProcess,		//释放此进程虚拟地址空间中的分配的内存页
  __inout  PULONG_PTR NumberOfPages,	//要释放的内存页数
  __in     PULONG_PTR UserPfnArray	//指向存储内存页帧成员的数组的指针
);
BOOL WINAPI MapUserPhysicalPages(	//将分配好的内存页映射到指定的地址
  __in  PVOID lpAddress,		//指向要重映射的内存区域的指针
  __in  ULONG_PTR NumberOfPages,	//要映射的内存页数
  __in  PULONG_PTR UserPfnArray		//指向要映射的内存页的指针
);

在看示例程序之前还有一些设置需要做,系统的本地安全策略需要设置。在win7下,打开“控制面板->系统和安全->管理工具->本地安全策略”,将当前用户添加到“锁定内存页面”,然后退出,重启(不重启一般不会生效! ).

32位系统设置最大内存

经过前面的准备(再啰嗦一点:确认你的电脑是4G以上内存;开启PAE让系统识别4G以上内存;设置本地安全策略),我们就可以通过按照代码做一个实验。

代码是从 MSDN 中的 AWE 示例修改而来的。具体过程见代码中的注释。如果您对本示例的源代码感兴趣,可以参考 MSDN。

#include "AWE_TEST.h"
#include 
#include 
#define MEMORY_REQUESTED ((2*1024+512)*1024*1024) //申请2.5G内存,测试机上只有4G内存,而且系统是window7,比较占内存.申请3G容易失败.
#define MEMORY_VIRTUAL 1024*1024*512		//申请长度0.5G的虚拟内存,即AWE窗口.
//检测"锁定内存页"权限的函数
BOOL LoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable);
void _cdecl main()
{
	BOOL bResult;                   // 通用bool变量
	ULONG_PTR NumberOfPages;        // 申请的内存页数
	ULONG_PTR NumberOfPagesInitial; // 初始的要申请的内存页数
	ULONG_PTR *aPFNs;               // 页信息,存储获取的内存页成员
	PVOID lpMemReserved;            // AWE窗口
	SYSTEM_INFO sSysInfo;           // 系统信息
	INT PFNArraySize;               // PFN队列所占的内存长度
	GetSystemInfo(&sSysInfo);  // 获取系统信息
	printf("This computer has page size %d./n", sSysInfo.dwPageSize);
	//计算要申请的内存页数.
	NumberOfPages = MEMORY_REQUESTED/sSysInfo.dwPageSize;
	printf ("Requesting %d pages of memory./n", NumberOfPages);
	// 计算PFN队列所占的内存长度
	PFNArraySize = NumberOfPages * sizeof (ULONG_PTR);
	printf ("Requesting a PFN array of %d bytes./n", PFNArraySize);
	aPFNs = (ULONG_PTR *) HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
	if (aPFNs == NULL) 
	{
		printf ("Failed to allocate on heap./n");
		return;
	}
	// 开启"锁定内存页"权限
	if( ! LoggedSetLockPagesPrivilege( GetCurrentProcess(), TRUE ) ) 
	{
		return;
	}
	// 分配物理内存,长度2.5GB
	NumberOfPagesInitial = NumberOfPages;
	bResult = AllocateUserPhysicalPages( GetCurrentProcess(),
		&NumberOfPages,
		aPFNs );
	if( bResult != TRUE ) 
	{
		printf("Cannot allocate physical pages (%u)/n", GetLastError() );
		return;
	}
	if( NumberOfPagesInitial != NumberOfPages ) 
	{
		printf("Allocated only %p pages./n", NumberOfPages );
		return;
	}
	// 保留长度0.5GB的虚拟内存块(这个内存块即AWE窗口)的地址
	lpMemReserved = VirtualAlloc( NULL,
		MEMORY_VIRTUAL,
		MEM_RESERVE | MEM_PHYSICAL,
		PAGE_READWRITE );
	if( lpMemReserved == NULL ) 
	{
		printf("Cannot reserve memory./n");
		return;
	}
	char *strTemp;
	for (int i=0;i<5;i++)
	{
		// 把物理内存映射到窗口中来
		// 分5次映射,每次映射0.5G物理内存到窗口中来.
		// 注意,在整个过程中,lpMenReserved的值都是不变的
		// 但是映射的实际物理内存却是不同的
		// 这段代码将申请的2.5G物理内存分5段依次映射到窗口中来
		// 并在每段的开头写入一串字符串.
		bResult = MapUserPhysicalPages( lpMemReserved,
			NumberOfPages/5,
			aPFNs+NumberOfPages/5*i);
		if( bResult != TRUE ) 
		{
			printf("MapUserPhysicalPages failed (%u)/n", GetLastError() );
			return;
		}
		// 写入字符串,虽然是写入同一个虚存地址,
		// 但是窗口映射的实际内存不同,所以是写入了不同的内存块中
		strTemp=(char*)lpMemReserved;
		sprintf(strTemp,"This is the %dth section!",i+1);
		// 解除映射
		bResult = MapUserPhysicalPages( lpMemReserved,
			NumberOfPages/5,
			NULL );
		if( bResult != TRUE ) 
		{
			printf("MapUserPhysicalPages failed (%u)/n", GetLastError() );
			return;
		}
	}
	// 现在再从5段内存中读出刚才写入的字符串
	for (int i=0;i<5;i++)
	{
		// 把物理内存映射到窗口中来
		bResult = MapUserPhysicalPages( lpMemReserved,
			NumberOfPages/5,
			aPFNs+NumberOfPages/5*i);
		if( bResult != TRUE ) 
		{
			printf("MapUserPhysicalPages failed (%u)/n", GetLastError() );
			return;
		}
		// 将映射到窗口中的不同内存块的字符串在屏幕中打印出来
		strTemp=(char*)lpMemReserved;
		printf("%s/n",strTemp);
		// 解除映射
		bResult = MapUserPhysicalPages( lpMemReserved,
			NumberOfPages/5,
			NULL );
		if( bResult != TRUE ) 
		{
			printf("MapUserPhysicalPages failed (%u)/n", GetLastError() );
			return;
		}
	}
	
	// 释放物理内存空间
	bResult = FreeUserPhysicalPages( GetCurrentProcess(),
		&NumberOfPages,
		aPFNs );
	if( bResult != TRUE ) 
	{
		printf("Cannot free physical pages, error %u./n", GetLastError());
		return;
	}
	// 释放虚拟内存地址
	bResult = VirtualFree( lpMemReserved,
		0,
		MEM_RELEASE );
	// 释放PFN队列空间
	bResult = HeapFree(GetProcessHeap(), 0, aPFNs);
	if( bResult != TRUE )
	{
		printf("Call to HeapFree has failed (%u)/n", GetLastError() );
	}
}
/*****************************************************************
输入:
HANDLE hProcess: 需要获得权限的进程的句柄
BOOL bEnable: 启用权限 (TRUE) 或 取消权限 (FALSE)?
返回值: TRUE 表示权限操作成功, FALSE 失败.
*****************************************************************/
BOOL
LoggedSetLockPagesPrivilege ( HANDLE hProcess,
							 BOOL bEnable)
{
	struct {
		DWORD Count;
		LUID_AND_ATTRIBUTES Privilege [1];
	} Info;
	HANDLE Token;
	BOOL Result;
	// 打开进程的安全信息
	Result = OpenProcessToken ( hProcess,
		TOKEN_ADJUST_PRIVILEGES,
		& Token);
	if( Result != TRUE ) 
	{
		printf( "Cannot open process token./n" );
		return FALSE;
	}
	// 开启 或 取消?
	Info.Count = 1;
	if( bEnable ) 
	{
		Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
	} 
	else 
	{
		Info.Privilege[0].Attributes = 0;
	}
	// 获得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;
	}
	// 修改权限
	Result = AdjustTokenPrivileges ( Token, FALSE,
		(PTOKEN_PRIVILEGES) &Info,
		0, NULL, NULL);
	// 检查修改结果
	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;
}


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-378997-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    每日福利
    热点图片
    拼命载入中...