为什么 .NET 内存占用非常大?

115 阅读4分钟

前言

.NET 占的内存大吗?大,非常大,不过也正是一种正常的现象。

10几年前我就用 VS2008 开发软件,那会的软件运行在 XP 系统上,也没有感觉占用内存大,不过到了后来,随着VS 版本的升级,功能的强大,编译出来的软件越来越大,运行系统也从XP 一路升级,win7、win10、win11,采购的成本、配置也越来越高,系统运行慢的声音也是越来越大,没办法我们一边优化软件,一边升级电脑的配置。

接下来我们就来,我们就详细的拆解一下这个问题。

一、.NET内存管理架构分析

.Net 占用内存大的核心原因是:分代 GC 管理机制、托管堆的预分配、JIT 编译换成以及运行时元素存储等。

1、CLR 运行时内存开销

JIT 编译器缓存,大约占内存 200M,用于存储编译后的机器码。

元数据存储,包括类型信息,反射数据以及数据集元数据等相关信息。

运行时服务,包括线程池、同步、一次性处理等机制。

2、分代垃圾回收机制

分代 GC 的内存回收机制的

垃圾回收器将堆上的内存分为了三代。

刚刚分配的对象位于第0代,在第一轮回收中存活的对象为第1代,而其他所有对象为第2代。

第0代和第1代对象就是所谓的短生存期(ephemeral)的代。CLR将第0代控制在一个相对较小的空间内(典型大小在几百KB至几MB)。当第0代填满时,GC就会触发第0代垃圾回收。第0代垃圾回收会频繁发生。

GC对第1代内存应用了相似空间限制(作为第2代的缓冲区),且第1代内存的回收也相对快速而频繁。一次完整的内存回收会包含第2代内存。

3、典型的 .NET 应用约占 1.2 G 内存左右

其中:CLR 运行时占 200M、托管堆 600M、大对象 250M、其他组件 150M。

二、其他技术占内存使用情况

技术栈典型内存约占(M)主要组成优势劣势
.Net1200CLR + 托管堆 + LOH + 其他开发效率高、内存安全内存开销大
Java1300JVM + 堆 + 元空间 + 其他生态成熟启动慢、内存开销大
C++80程序代码 + 堆栈 + 其他性能好、内存可控开发复杂、易出错
Node.js200V8引擎 + 堆 + 其他开发快速、生态丰富单线程
Python400解释器 + 对象 + 模块简单易学、库丰富性能较低

三、.NET 内存优化策略

1、对象生命周期管理

使用 using 语句管理资源

using (var fileStream = new FileStream("data.txt", FileMode.Open))
using (var reader = new StreamReader(fileStream))
{
    // 自动释放资源,即使发生异常
     return reader.ReadToEnd();
}

2)对象池模式实现

2、数据结构优化

避免使用大对象

3、GC 配置优化

项目文件配置

运行时 GC 调优

4、字符串优化策略

StringBuilder优化

字符串驻留优化

其实, .NET 应用占用内存大是有道理,因为 .NET 提高了开发效率相比 C++ 而言,开发效率提高了很多倍,而且动态内存管理避免了大量的潜在 Bug。现在单片成本不高,相比 .NET 占的这点内存优势不要太明显,你说呢?

关键词

.NET、内存占用、GC、CLR、JIT、对象池、字符串优化、托管堆、内存管理、运行时

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:全小鱼

出处:zhihu.com/question/662756682/answer/1942177727990994219

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!