一:背景

1. 讲故事

最近接连遇到了几起 2G 虚拟地址紧张 导致的程序崩溃,基本上 90% 都集中在医疗行业,真的很无语,他们用的都是一些上古的 XP,Windows7 x86,我也知道技术人很难也基本无法推动硬件系统和设备的升级,这里蕴含了巨大的人情世故。

写这一篇的目的是想系统化的整理一下如何配置 3G 开关让程序吃到更多的内存,让程序崩溃的不那么频繁一些,以及如何验证是否成功开启!

二:32位操作系统

1. 测试代码

首先大家要有一个理念:就是 32bit系统上跑的程序,默认只能吃到 2G 内存,因为这涉及到公平,用户态吃2G,内核态吃2G,为了方便演示,向一个 List 塞入 5000w 的 string,大概占用 2G 内存,然后把程序跑在 Windows7 32bit 操作系统上。


static void Main(string[] args)
{
var list = new List<string>(); for (int i = 0; i < 50000000; i++)
{
list.Add(i.ToString()); if (i % 10000 == 0) { Console.WriteLine($"i={i}"); }
}
Console.WriteLine("ok");
Console.ReadLine();
}

从图中可以清楚的看到当内存到了631M 的时候就扛不住了,可能有些朋友好奇,为什么才这么点就不行了,这是因为 List 的底层是 2倍 扩容,所以内存大概会涨到 0.63G + 1.2G = 1.83G

有些朋友可能会问,这不是还没到2G吗?一般来说内存到了 1.2G+ 的时候崩溃风险就会剧增,这个要谨记!

2. 如何解决

刚才也说了,医疗行业现状如此,只能通过人情世故去推动,那这 2G 数据真的无处安放吗? 这时候就只能启动 3G 开关,那如何启动呢?

  1. 开启程序级的 Large Address Aware

这个 Large Address Aware 字段俗称大地址,途径就是在 PE 头里打开一个开关,让Windows加载器决定是否给程序打开 3G 的绿色通道。

当然看 PE头 的工具有很多,对于.NET程序个人感觉最好的就是用 DnSpy,它把 File Header 中的 Characteristics 字段具化了,我们选中 Large Address Aware 复选框然后保存,截图如下:

  1. 开启机器级别 3G 开关

在32bit操作系统上让用户态程序吃到 3G 内存这对操作系统来说是非常谨慎的,毕竟这对内核态是非常不公平的,言外之意就是让出自己的 1G 给用户态,这骚操作可能就会把自己坑惨,谨慎起见需要人工开启机器级别的 3G 开关,命令如下:


bcdedit /set IncreaseUserVa 3072

做了这两步之后,继续让程序跑起来,截图如下:

从图中可以清晰的看到,终于有出息了。

更多操作系统配置,可参考这篇文章:https://www.autodesk.com.cn/support/technical/article/caas/sfdcarticles/sfdcarticles/CHS/How-to-enable-a-3GB-switch-on-Windows-Vista-Windows-7-or-Windows-XP-s.html?v=2018

3. 如何验证是否开启了 3G

这确实是一个好问题,最简单的方式就是用!address 观察下地址空间。


0:000> !address BaseAddr EndAddr+1 RgnSize Type State Protect Usage
-----------------------------------------------------------------------------------------------
...
+ bffde000 bffdf000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE TEB [~0; aa4.fb8]
+ bffdf000 bffe0000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE PEB [aa4]
+ bffe0000 bfff0000 10000 MEM_PRIVATE MEM_RESERVE PAGE_NOACCESS <unknown> 0:000> ? bfff0000/0x100000
Evaluate expression: 3071 = 00000bff

上面卦中的 bfff0000 转换过来就是 3G,如果你看到的是这个值,那就恭喜你啦!

如果有朋友想问如何验证 dump程序是否开启了大地址,这个可以用windbg提供的 !dh 命令。


0:000> lm
start end module name
001e0000 001e8000 ConsoleApp4 C (pdb symbols) D:\code\MyApplication\ConsoleApp4\obj\x86\Debug\ConsoleApp4.pdb
66dd0000 678c8000 mscorlib_ni (deferred)
678d0000 67e61000 mscorwks (deferred)
6c7a0000 6c83b000 msvcr80 (deferred)
...
0:000> !dh ConsoleApp4 File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
3 number of sections
EDB20AC7 time date stamp
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
122 characteristics
Executable
App can handle >2gb addresses
32 bit word machine

如果看到上面卦中的 App can handle >2gb addresses 字样就表示你开启成功啦!

三:64位操作系统

1. 如何吃更多内存

在 x64系统上就方便多了, 只需要做第一步开启 Large Address Aware 即可,毕竟 x64系统 的虚拟地址空间不要太充足,在 48根地址总线上就是2的48次方,所以开启大地址后,会给 x32 程序4G的寻址空间,即 2 的 32 次方。

接下来直接把刚才的 ConsoleApp4.exe 程序从 Windows7 x86 搬迁到 Windows 10 x64 系统上,然后用 windbg 附加运行, 跑完后使用 !address 查看。


0:007> !address BaseAddr EndAddr+1 RgnSize Type State Protect Usage
-----------------------------------------------------------------------------------------------
+ 0 c60000 c60000 MEM_FREE PAGE_NOACCESS Free
...
+ ff671000 ff680000 f000 MEM_FREE PAGE_NOACCESS Free
+ ff680000 ff6b3000 33000 MEM_MAPPED MEM_COMMIT PAGE_READONLY Other [NLS Tables]
+ ff6b3000 ffff0000 93d000 MEM_FREE PAGE_NOACCESS Free 0:007> ? ffff0000 /0x100000
Evaluate expression: 4095 = 00000fff

如果在你的卦中也看到了上面的 ffff0000 ,那就恭喜你,你程序的内存寻址空间扩展到了 4G 。

三:总结

本篇说了这么多,其实都是一些不得已而为之的事情,很心酸,这世上很多东西不是靠技术就能解决的,更需要靠人情事故!

对 .NET程序2G虚拟地址紧张崩溃 的最后一次反思的更多相关文章

  1. Android DevArt4:IntentFilter学习及深入~问题描述:在不指定具体action前提下,如果有两个以上的Activity,具有完全相同的intent-filter,项目同步是否会出现异常?程序运行是否会崩溃?

    概述:GitHub IntentFilter意图过滤器,三种匹配规则:action.category.data 重点:过滤规则中必须设置 '<category android:name=&quo ...

  2. Qt程序继承QApplication发生崩溃的原因

    一.前情介绍 QApplication是Qt开发中经常用到的一个类,用来管理应用程序的生命周期.跟其相关的类还有QCoreApplication和QGuiApplication,分别用于不同场景下为应 ...

  3. golang程序因未知错误崩溃时如何记录异常

    开发服务器程序时如果未经过充分测试, 服务稳定运行一段时间后会突然崩溃退出.一般是因为程序中出现了某个未捕获的异常. 这类问题属于偶现的,且需要服务器运行一段时间之后才会出现,难以定位有问题的代码段. ...

  4. Qt5.11.2 VS2015编译activemq发送程序 _ITERATOR_DEBUG_LEVEL错误和崩溃解决

    1.问题描述: 运行环境是 win10 64位系统,开发环境是VS2015 ,Qt 5.11.2.开发activemq发送程序,遇到问题 (1)Qt5AxContainer.lib error LNK ...

  5. 论try/catch的重要性,我们经常遇到代码出现无法调试的错误,程序退出的时候崩溃。这跟我们代码日常保护的习惯息息相关。

    每当构造函数或析构函数中出现溢出,会导致调试非常困难,而使用try/catch来处理构造中的初始化就非常重要了. 如上图,在构造函数中,我们的很多初始化动作会放在这里,但是却忽视了,一旦初始化出错了, ...

  6. 记一次 .NET 差旅管理后台 CPU 爆高分析

    一:背景 1. 讲故事 前段时间有位朋友在微信上找到我,说他的 web 系统 cpu 运行一段时候后就爆高了,让我帮忙看一下是怎么回事,那就看吧,声明一下,我看 dump 是免费的,主要是锤炼自己技术 ...

  7. 你的java/c/c++程序崩溃了?揭秘段错误(Segmentation fault)(3)

    前言 接上两篇: 你的C/C++程序为什么无法运行?揭秘Segmentation fault (1) 你的C/C++程序为什么无法运行?揭秘Segmentation fault (2) 写到这里,越跟 ...

  8. 关于编写Java程序让Jvm崩溃

    今天在书上看到一个作者提出一个问题“怎样通过编写Java代码让Jvm崩溃”,我看了之后也不懂.带着问题查了一下,百度知道里面有这样一个答案: package jvm; public class Cra ...

  9. 水火难容:同步方法调用async方法引发的ASP.NET应用程序崩溃

    之前只知道在同步方法中调用异步(async)方法时,如果用.Result等待调用结果,会造成线程死锁(deadlock).自己也吃过这个苦头,详见等到花儿也谢了的await. 昨天一个偶然的情况,造成 ...

  10. [CareerCup] 12.2 Find the Reason of Crash 找到程序崩溃的原因

    12.2 You are given the source to an application which crashes when it is run. After running it ten t ...

随机推荐

  1. VS Code 有哪些好用的插件呢?【持续更新】

    一.画图工具:vscode-drawio   功能:在 VSCode 中画流程图.数据流图等等.        使用方法:     创建一个后缀名为 .drawio 的文件,然后用 VSCode 打开 ...

  2. 5、Spring之bean的作用域和生命周期

    5.1.bean的作用域 5.1.1.单例(默认且常用) 5.1.1.1.配置bean 注意:当bean不配置scope属性时,默认是singleton(单例) <?xml version=&q ...

  3. 4.4 C++ Boost 数据集序列化库

    Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量.可移植.高效的C应用程序.Boost库可以作为标准C库的后备,通常被称为准标准 ...

  4. 部署属于自己的New bing Ai

    该项目来源 https://github.com/adams549659584/go-proxy-bingai 项目体验地址 https://bing.vcanbb.top/web/#/ 项目介绍 基 ...

  5. 0×03 Vulnhub 靶机渗透总结之 KIOPTRIX: LEVEL 1.2 (#3) SQL注入+sudo提权

    0×03 Vulnhub 靶机渗透总结之 KIOPTRIX: LEVEL 1.2 (#3) 系列专栏:Vulnhub靶机渗透系列 欢迎大佬:点赞️收藏关注 首发时间: 2023年8月22日 如有错误 ...

  6. 京东获得JD商品详情 API 返回值说明

    ​ item_get-获得JD商品详情  API测试 onebound.jd.item_get 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) ...

  7. AI测试,给出的答案还挺那么回事儿的~

    今天文心一言全民开放了,所有人都可以正常下载使用了,不用像之前一样排队等号了.之前内测阶段倒也体验过,技术人员总是喜欢尝鲜,第一时间拿到邀请码后就各种调戏了TA一番,那时觉得给出的答案总有些差强人意, ...

  8. vue3+ts Axios封装—重复请求拦截

    创建好vue3项目 1.安装Axios与Element Plus Axios安装 npm install axios Element Plus 安装 官网入口:https://element-plus ...

  9. KRPANO开发拍摄拼图视频常用软件分享

    KRPano开发拍摄拼图视频常用软件分享,包含了KRPano开发,拼图,视频等软件. 包括如下软件: 全景照片拼接,全景照片查看,全景视频拼接,全景视频查看,全景视频插件,全景漫游制作,KRPano资 ...

  10. Understanding UML in seconds

    UML 是一种分析设计语言,也就是一种建模语言. UML结构解析 UML其结构主要包括以下几个部分: 视图(View) 多个图形组成的集合: 图(Diagram) 图的种类有13种图,但常用的也就两种 ...