记32位程序(使用3gb用户虚拟内存)使用D3DX9导致的一个崩溃的问题
为了增加32位程序的用户虚拟内存的使用量,我们使用了/LARGEADDRESSAWARE编译选项来使32位程序可能使用到3gb的内存,能否使用到3gb内存也跟平台、系统和设置有关系,现摘抄部分作为参考具体可参考微软官方网站[i]:
Limits on memory and address space vary by platform, operating system, and by whether the IMAGE_FILE_LARGE_ADDRESS_AWARE value of the LOADED_IMAGE structure and 4-gigabyte tuning (4GT) are in use. IMAGE_FILE_LARGE_ADDRESS_AWARE is set or cleared by using the /LARGEADDRESSAWARE linker option.
4-gigabyte tuning (4GT), also known as application memory tuning, or the /3GB switch, is a technology (only applicable to 32 bit systems) that alters the amount of virtual address space available to user mode applications. Enabling this technology reduces the overall size of the system virtual address space and therefore system resource maximums. For more information, see What is 4GT.
Limits on physical memory for 32-bit platforms also depend on the Physical Address Extension (PAE), which allows 32-bit Windows systems to use more than 4 GB of physical memory.
Memory and Address Space Limits
The following table specifies the limits on memory and address space for supported releases of Windows. Unless otherwise noted, the limits in this table apply to all supported releases.
Memory type |
Limit on X86 |
Limit in 64-bit Windows |
User-mode virtual address space for each 32-bit process |
2 GB Up to 3 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE and 4GT |
2 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE cleared (default) 4 GB with IMAGE_FILE_LARGE_ADDRESS_AWARE set |
使用更多的用户虚拟地址好处就不说了,下面说下我们遇到的一个比较难解决的崩溃,就是引擎在解析shader的时候,有机率崩溃,下面是示例代码:
LPD3DXINCLUDE pInclude = NULL;
DWORD dwFlag = ;
dwFlag |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
LPD3DXBUFFER pErrorBuffer = NULL;
LPD3DXCONSTANTTABLE pConstantTable = NULL;
HRESULT hr = D3DXCompileShader (m_strSource.c_str(), m_strSource.size(), ¯oVec[],
pInclude, m_strEntryFunc.c_str(), m_strProfile.c_str(), dwFlag,
&m_pShaderBuffer, &pErrorBuffer, &pConstantTable); if (hr != S_OK)
{
// 错误处理
} // if D3DXCONSTANTTABLE_DESC desc;
pConstantTable->GetDesc(&desc);
for (UINT i = ; i < desc.Constants; ++i)
{
D3DXCONSTANT_DESC constantDesc;
D3DXHANDLE handle = pConstantTable->GetConstant(NULL, i);
UINT numCount;
hr = pConstantTable->GetConstantDesc(handle, &constantDesc, &numCount);
VERIFY_D3D_RESULT (hr);
if (constantDesc.RegisterSet == D3DXRS_SAMPLER)
{
// 相应的操作
}
} // for
崩溃行在hr = pConstantTable->GetConstantDesc(handle, &constantDesc, &numCount);一开始崩溃看了一下最后跟到d3d9x里面崩溃,具体原因也就不好查找,所以也没仔细去管,但是后来发现崩溃的机率还是有点大的,一开始怀疑是编译的shader有问题,但是从内存中拿出编译好的二进制跟离线生成的二进制比较并没有任何差异,问题也暂时搁置。后来抓住一次崩溃的机会对d3d9x的汇编代码进行了跟踪调试,经过一系列的跟踪比对,发现一处代码很可疑,就是GetConstantDesc这个函数,函数声明为STDMETHOD(GetConstantDesc)(THIS_ D3DXHANDLE hConstant, D3DXCONSTANT_DESC *pConstantDesc, UINT *pCount) PURE,汇编代码如下:
D3DXShader::CConstantTable::GetConstantDesc:
0F52AFF0 mov edi,edi
0F52AFF2 push ebp
0F52AFF3 mov ebp,esp
0F52AFF5 push esi
0F52AFF6 mov esi,dword ptr [ebp+10h]
0F52AFF9 push edi
0F52AFFA mov edi,dword ptr [ebp+14h]
0F52AFFD test esi,esi
0F52AFFF jne D3DXShader::CConstantTable::GetConstantDesc+1Ch (0F52B00Ch)
0F52B001 test edi,edi
0F52B003 jne D3DXShader::CConstantTable::GetConstantDesc+1Ch (0F52B00Ch)
0F52B005 mov eax,8876086Ch
0F52B00A jmp D3DXShader::CConstantTable::GetConstantDesc+8Dh (0F52B07Dh)
0F52B00C mov ecx,dword ptr [ebp+0Ch] // ecx 中即为hConstant
0F52B00F test ecx,ecx
0F52B011 je D3DXShader::CConstantTable::GetConstantDesc+15h (0F52B005h)
0F52B013 mov edx,dword ptr [ebp+]
0F52B016 mov eax,dword ptr [edx+]
0F52B019 or eax,ecx ;注意此处代码,用来判断ecx的最高位是否是1
; 如果为1则不跳转,否则跳转到绿色所示的代码处开始执行,这也是崩溃的开始,最终在调用
; 红色所示的函数时/发生了崩溃。
0F52B01B jge D3DXShader::CConstantTable::GetConstantDesc+31h (0F52B021h)
0F52B01D neg ecx ; 至于此处为什么要取负值,请详见下面的具体说明。
0F52B01F jmp D3DXShader::CConstantTable::GetConstantDesc+44h (0F52B034h)
0F52B021 lea eax,[ebp+10h]
0F52B024 push eax
0F52B025 push ecx
0F52B026 mov ecx,edx
0F52B028 call D3DXShader::CConstantTable::FindConstantByName (0F52AE0Dh)
0F52B02D test eax,eax
0F52B02F js D3DXShader::CConstantTable::GetConstantDesc+8Dh (0F52B07Dh)
0F52B031 mov ecx,dword ptr [ebp+10h]
0F52B034 xor edx,edx
0F52B036 xor eax,eax
0F52B038 inc edx
0F52B039 push ebx
0F52B03A mov ebx,ecx
0F52B03C test ecx,ecx
0F52B03E je D3DXShader::CConstantTable::GetConstantDesc+58h (0F52B048h)
0F52B040 mov ebx,dword ptr [ebx+24h]
0F52B043 inc eax
0F52B044 test ebx,ebx
0F52B046 jne D3DXShader::CConstantTable::GetConstantDesc+50h (0F52B040h)
0F52B048 pop ebx
0F52B049 test edi,edi
0F52B04B je D3DXShader::CConstantTable::GetConstantDesc+6Ch (0F52B05Ch)
0F52B04D cmp dword ptr [edi],
0F52B050 je D3DXShader::CConstantTable::GetConstantDesc+64h (0F52B054h)
0F52B052 mov edx,dword ptr [edi]
0F52B054 cmp edx,eax
0F52B056 jbe D3DXShader::CConstantTable::GetConstantDesc+6Ah (0F52B05Ah)
0F52B058 mov edx,eax
0F52B05A mov dword ptr [edi],eax
0F52B05C test esi,esi
0F52B05E je D3DXShader::CConstantTable::GetConstantDesc+8Bh (0F52B07Bh)
0F52B060 jmp D3DXShader::CConstantTable::GetConstantDesc+87h (0F52B077h)
0F52B062 test edx,edx
0F52B064 je D3DXShader::CConstantTable::GetConstantDesc+8Bh (0F52B07Bh)
0F52B066 push esi
0F52B067 call D3DXShader::CConstant::GetDesc (0F5275B6h)
0F52B06C test eax,eax
0F52B06E js D3DXShader::CConstantTable::GetConstantDesc+8Dh (0F52B07Dh)
0F52B070 mov ecx,dword ptr [ecx+24h]
0F52B073 add esi,30h
0F52B076 dec edx
0F52B077 test ecx,ecx
0F52B079 jne D3DXShader::CConstantTable::GetConstantDesc+72h (0F52B062h)
0F52B07B xor eax,eax
0F52B07D pop edi
0F52B07E pop esi
0F52B07F pop ebp
0F52B080 ret 10h
上面的蓝色的代码处为什么会取负值呢,让我们把GetConstant的汇编代码帖出来读者就能看出来了:
D3DXShader::CConstantTable::GetConstant:
0F52B0D0 mov edi,edi
0F52B0D2 push ebp
0F52B0D3 mov ebp,esp
0F52B0D5 mov ecx,dword ptr [ebp+0Ch]
0F52B0D8 test ecx,ecx
0F52B0DA jne D3DXShader::CConstantTable::GetConstant+23h (0F52B0F3h)
0F52B0DC mov ecx,dword ptr [ebp+10h]
0F52B0DF mov eax,dword ptr [ebp+]
0F52B0E2 cmp ecx,dword ptr [eax+1Ch]
0F52B0E5 jb D3DXShader::CConstantTable::GetConstant+1Bh (0F52B0EBh)
0F52B0E7 xor eax,eax
0F52B0E9 jmp D3DXShader::CConstantTable::GetConstant+52h (0F52B122h)
0F52B0EB mov eax,dword ptr [eax+18h]
0F52B0EE mov eax,dword ptr [eax+ecx*]
0F52B0F1 jmp D3DXShader::CConstantTable::GetConstant+50h (0F52B120h)
0F52B0F3 mov edx,dword ptr [ebp+]
0F52B0F6 mov eax,dword ptr [edx+]
0F52B0F9 or eax,ecx
0F52B0FB jge D3DXShader::CConstantTable::GetConstant+31h (0F52B101h)
0F52B0FD neg ecx
0F52B0FF jmp D3DXShader::CConstantTable::GetConstant+44h (0F52B114h)
0F52B101 lea eax,[ebp+]
0F52B104 push eax
0F52B105 push ecx
0F52B106 mov ecx,edx
0F52B108 call D3DXShader::CConstantTable::FindConstantByName (0F52AE0Dh)
0F52B10D test eax,eax
0F52B10F js D3DXShader::CConstantTable::GetConstant+17h (0F52B0E7h)
0F52B111 mov ecx,dword ptr [ebp+]
0F52B114 push dword ptr [ebp+10h]
0F52B117 call D3DXShader::CConstant::GetConstantMember (0F52765Fh)
0F52B11C test eax,eax
0F52B11E je D3DXShader::CConstantTable::GetConstant+17h (0F52B0E7h)
0F52B120 neg eax ; 此处对要返回的结果进行了取负值操作,所以在下面调用
; GetConstantDesc 的时候需要对其进行取负值操作,得到最终的结果,至于为什么这样做
; 目前不是特别清楚,希望了解的人可以告知。
0F52B122 pop ebp
0F52B123 ret 0Ch
//----------------------------------------------------------------------------
// D3DXHANDLE:
// -----------
// Handle values used to efficiently reference shader and effect parameters.
// Strings can be used as handles. However, handles are not always strings.
//---------------------------------------------------------------------------- #ifndef D3DXFX_LARGEADDRESS_HANDLE
typedef LPCSTR D3DXHANDLE;
#else
typedef UINT_PTR D3DXHANDLE;
#endif
typedef D3DXHANDLE *LPD3DXHANDLE;
HRESULT D3DXCompileShader(
_In_ LPCSTR pSrcData,
_In_ UINT srcDataLen,
_In_ const D3DXMACRO *pDefines,
_In_ LPD3DXINCLUDE pInclude,
_In_ LPCSTR pFunctionName,
_In_ LPCSTR pProfile,
_In_ DWORD Flags,
_Out_ LPD3DXBUFFER *ppShader,
_Out_ LPD3DXBUFFER *ppErrorMsgs,
_Out_ LPD3DXCONSTANTTABLE *ppConstantTable
);
Parameters
ppConstantTable [out]
Type: LPD3DXCONSTANTTABLE*
Returns an ID3DXConstantTable interface, which can be used to access shader constants. This value can be NULL. If you compile your application as large address aware (that is, you use the /LARGEADDRESSAWARE linker option to handle addresses larger than 2 GB), you cannot use this parameter and must set it to NULL. Instead, you must use the D3DXGetShaderConstantTableEx function to retrieve the shader-constant table that is embedded inside the shader. In this D3DXGetShaderConstantTableEx call, you must pass the D3DXCONSTTABLE_LARGEADDRESSAWARE flag to the Flags parameter to specify to access up to 4 GB of virtual address space.[ii]
也就是说如果开启了3gb用户虚拟地址空间,那么我们在获取Shader常量表时就必须使用D3DXGetShaderConstantTableEx并且加上D3DXCONSTTABLE_LARGEADDRESSAWARE标记。到此为止,崩溃问题已经完美解决了。希望没有白白浪费你的时间,能有所收获。当然,如果文中有描述不对的地方也请指正。
记32位程序(使用3gb用户虚拟内存)使用D3DX9导致的一个崩溃的问题的更多相关文章
- 64位系统上运行32位程序能否申请到8G内存?
申请不到,因为64为系统在运行32位程序的时候只是为了向下兼容而已,对于32位程序来讲,申请8G的存储空间没有任何意义,因为32位的程序最大寻址空间只有4G,32位程序在编译之后的机器代码也只有32位 ...
- 转:如何在32位程序中突破地址空间4G的限制
//如何在32位程序中突破地址空间4G的限制 //首先要获得内存中锁定页的权限 #define _WIN32_WINNT 0x0501 //xp系统 #include <windows.h> ...
- 使 32 位程序使用大于 2GB 的内存
不管在 32 位 Windows 上还是在 64 位 Windows 上,32 位的应用程序都只能使用最大 2GB 的内存,这是我们司空见惯的一个设定.但其实 Windows 提供了一些方法让我们打破 ...
- 记32位Oracle客户端登录报12560协议适配器错误的解决办法
国庆买了一台新电脑ThinkPad E431,i5双核CPU,8G内存,硬盘比较坑爹5400转的500G,重点是预装win8的64位简体中文版.大学时买了第一台电脑神舟笔记本,因为神舟电脑便宜,所以没 ...
- 32位程序调用Oracle11gR2数据库libclntsh.so失败
[问题描述]32位程序调用Oracle11gR2数据库的libclntsh.so库时会返回失败. [问题原因]32位程序只能调用32位的Oracle客户端实例包,而R2数据库默认安装完毕后是没有lib ...
- C# 32位程序访问64位系统注册表
原文:C# 32位程序访问64位系统注册表 我的上一篇文章已经阐述了“32位程序和64位程序在64位平台上读\写注册表的区别”,那么接下来将要回答上篇所留下来的一个问题:32位程序如何访问64位系统注 ...
- 64位Ubuntu运行32位程序时报文件不存在(No such file or Directory)的一种解决办法
尝试在64位Ubuntu下面运行32位程序时, 一直说 文件不存在(No such file or directory), 我只想说++. 你tm说个文件格式不正确不就好了? 非得说个文件不存在! 真 ...
- Ubuntu14.04 64位运行32位程序
最近公司新增的机器安装Ubuntu14.04 64bit导致之前在32bit下编译的Qt工具软件无法运行. 于是google的了一下找到一些解决办法,但不能保证全部32bit的Qt程序都能正常,测试了 ...
- Linux 64位编译\链接32位程序
测试机器:Ubuntu14.04 64位 gcc编译32位程序,添加参数-m32: $ gcc -c -fno-builtin -m32 TinyHelloWorld.c ld链接32位代码,添加参数 ...
随机推荐
- PHP 中和 HTTP 相关的函数及使用
① get_headers 方法:取得服务器响应一个 HTTP 请求所发送的所有标头 例如: <?php $httpinfo = get_headers('http://www.baidu.co ...
- redis列表list
Redis Rpush 命令 Redis 列表(List) Redis Rpush 命令用于将一个或多个值插入到列表的尾部(最右边). 如果列表不存在,一个空列表会被创建并执行 RPUSH 操作. ...
- Hibernate + proxool 连接数超过最大允许连接数
主要原因是操作完成没有释放连接,在Hibernate中增加设定 <prop key="hibernate.connection.release_mode">after_ ...
- 解决电脑访问Discuz!手机版(支持触屏版)
discuz电脑访问手机版的方法现在需要来修改一下2个文件,即可用电脑浏览discuz的手机版本:找到./source/function/function_core.php 文件,查找 : funct ...
- mysql默认字符集修改
(1) 最简单的修改方法,就是修改mysql的my.ini文件中的字符集键值,添加 [mysql] default-character-set = utf8 [mysqld] character_se ...
- php常用代码
$total_count = mysql_num_rows($rslt);//返回记录条数 date("ymdHis");//130618104741 注:年份没有前两位 PHP手 ...
- random circle
<!doctype html><meta charset="utf-8"><html><head><title>D3 t ...
- js 和 jquery 获取页面和滚动条的高度 视口高度文档高度
js 和 jquery 获取页面和滚动条的高度 //页面位置及窗口大小 function GetPageSize() { var scrW, scrH; if(window.innerHeight & ...
- ASP.NET WebForm与ASP.NET MVC的不同点
ASP.NET WebForm ASP.NET MVC ASP.NET Web Form 遵循传统的事件驱动开发模型 ASP.NET MVC是轻量级的遵循MVC模式的请求处理响应的基本开发模型 ASP ...
- Oozie协作框架
一:概述 1.大数据协作框架 2.Hadoop的任务调度 3.Oozie的三大功能 Oozie Workflow jobs Oozie Coordinator jobs Oozie Bundle 4. ...