通过代码实现 OutOfMemory

Intro

来尝试写一个发生 OutOfMemoryException 的代码吧,开启煞笔代码第三篇 —— OutofMemory

OutOfMemory

OutOfMemory 顾名思义就是内存不足,在 .NET 中当内存不足的时候就会抛出 OutOfMemoryException 的异常。

想要触发 OutOfMemoryException 就要满足内存不足的条件,在 .NET Framework 中可能就只能一直分配内存直到内存不足,再没有足够的内存可以分配了,在 .NET Core 3.x 版本以后,微软引入了一些 GC 的配置,我们可以通过这些配置来指定最大的 GC 内存,这样我们就可以实现触发 OutOfMemoryException 而不影响其他应用程序正常运行的目标了。在 .NET 5 中我们又可以更进一步更精细的控制 GC 使用的内存了,在 .NET 5 中我们可以针对每个堆(SOH/LOH/POH)来设置内存限制。

GC 堆内存限制配置

我们测试的示例使用限制 GC 堆大小 (Heap Limit) 的方式来限制应用程序的内存占用以免影响到别的应用程序正常运行(该配置只针对 64 位电脑有效,现在的电脑应该大多都是64位吧)。

配置的方式有两种,一种是通过环境变量来配置,一种是通过 runtime.config.json 来配置

通过环境变量配置 COMPlus_GCHeapHardLimit 为要配置的内存大小,需要注意的是通过环境变量配置的时候指定的值需要是十六进制的值,通过 runtimeconfig.json 配置的时候是直接用十进制的数值

因为我们只是想简单的测试一下,不能影响别的应用程序,而且不能在代码里配置当前进程的环境变量,因为进程启动的时候 GC 的配置就已经加载好了,在代码里配置当前进程的环境变量来改变 GC 配置是不会生效的,所以我们选择配置 runtimeconfig.json 来测试,在项目的 bin 目录下可以找到 runtimeconfig.json 文件,我们修改这一个文件即可(使用 runtimeconfig.json 的时候需要注意先生成一下,然后再更新 runtimeconfig.json 文件)

测试配置如下:

{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "3.1.0"
},
"configProperties": {
"System.GC.HeapHardLimit": 1048576
}
}
}

测试代码

测试代码如下:

Console.ReadLine();
var bytes = GC.GetTotalAllocatedBytes();
Console.WriteLine($"AllocatedBytes: { bytes } bytes");
var list = new List<byte[]>();
try
{
while (true)
{
list.Add(new byte[85000]);
}
}
catch (OutOfMemoryException)
{
Console.WriteLine(nameof(OutOfMemoryException));
Console.WriteLine(list.Count);
bytes = GC.GetTotalAllocatedBytes();
Console.WriteLine($"AllocatedBytes: { bytes } bytes");
}
Console.ReadLine();

测试输出如下:

上面的测试代码使用的 byte 数组的长度是 85000 的原因是,当要分配的对象大于等于 85k(85000)时会直接分配到大对象堆中,正好可以测试一下。

我们使用微软的 dotnet dump 诊断工具来测试一下

第一次 dump 是在 list 对象创建之前进行的,第二次 dump 是发生 OutOfMemory 之后的

从上面的 dump 结果可以看的出来,byte 数组的对象确实是分配在大对象堆(LOH)上的,几乎所有的内存分配都在大对象堆中,有一些小对象从0 代升到了 1代。

More

上面的测试代码使用的 byte 数组的长度是 85000 ,你测试的时候也可以使用更大的值,或者直接使用 int.MaxValue

在前面的 StackOverflow 文章中,有网友评论说,他们之前遇到的一个 StackOverflow 示例常常伴随着 OutOfMemory ,递归和这种方式有点类似,都是要一直创建新的对象,分配新的内存。

除此之外,还有哪些更简单的方式吗?欢迎补充

References

最新文章

  1. 解析大型.NET ERP系统 灵活复杂的界面控件Infragistics WinForms
  2. Matlab中常用机器学习函数
  3. SQLServer异步调用,批量复制
  4. Android -- 是时候来了解一波EventBus了
  5. 用python理解web并发模型
  6. php正则失效-最大回溯(pcre.backtrack_limit)/递归限制
  7. [WebKit]浏览器的加载与页面性能优化
  8. C#中引用(ref关键字)参数
  9. win10 下安装、配置、启动mysql
  10. 今天上传公司服务器出现的.net framework版本错误问题
  11. 富文本编辑器嵌入指定html代码
  12. javascript 腾讯ABS云平台面试题及面试经历
  13. 新概念英语(1-127)A famous actoress(女演员)
  14. Ubuntu18.04安装netstat
  15. echarts入门
  16. html表格的基本用法
  17. cacheManager ABP中的缓存
  18. Arrays.copyOfRange()
  19. Oracle EBS AP更新供应商地址
  20. Chapter 7(图)

热门文章

  1. nacos快速安装
  2. 关于window服务器中新建的普通用户无法登录远程桌面
  3. MyBatis学习(四)代码生成器MyBatis-Generator
  4. (最新 9000 字 )Spring Boot 配置特性解析
  5. JavaScript,你好!
  6. Git源代码管理笔记
  7. Python 中的是那种路径
  8. Python-去除字符串中不想要的字符
  9. mysql-17-procedure
  10. STM32的CCM RAM