构建高性能ASP.NET站点 第七章 如何解决内存的问题(前篇)—托管资源优化—垃圾回收机制深度剖析

简介:
构建高性能ASP.NET 站点  第七章  如何解决内存的问题( 前篇)— 托管资源优化垃圾回收机制剖析
    前言:本章主要详细的讲述如何因内存问题而导致的性能问题,很多的时候都是深入.NET 内核进行分析,然后给出解决方案,同时,本系列的其他文章,也争取做到:深入浅出。
 
   本篇是为后面的做个铺垫,而且比较的精彩。只有真正的理解了本篇,后面才可以顺利的走下去。
 
本篇的议题如下:
内存问题概述( 前篇)
托管资源优化(前篇)
          对象的生命周期(前篇)
          对象的 代“(前篇)
          大对象堆(LOH)  (前篇)
         CLR 计数器的使用          (前篇)
         CLR Profiler 的使用(中篇)
          垃圾回收器的不同版本(中篇)
          对象使用注意事项(中篇)
          常用优化措施(后篇)
非托管资源优化
Session 会话的优化
 
   内存问题概述
    和CPU 一样,内存也是一个直接影响服务端性能的重要的硬件资源。
   一般来说,如果服务端内存不足,从导致以下两个问题产生:
1.        导致服务端把一些原本要写到内存中的数据,写到硬盘上面。这样不仅仅加大了CPU 和磁盘的I/O 操作,同时也延长了读取这些数据的时间。
2.        阻止了一些缓存策略的使用。
 
   对于内存不足,一直最快最直接的方式就是去买内存条加在服务器上面。但是这样存在一个隐患的问题就是:如果加了新的内存之后,服务端又面临内存不足的问题,我们不可能无止境的加内存条,那么我们就必须从站点本身来解决这个问题,例如从服务端的配置,对站点的代码进行分析,优化。
 
   托管资源优化
对于托管资源,相信大家并不陌生了,简单的说就是:在C# 的托管堆上面创建的资源,或者说通过new 产生的对象。
在深入讲解之前,我们首先来看看对象的生命周期
 
   对象的生命周期
当我们用new 关键字创建了一个对象的时候,这个对象就被分配到CRL 托管堆上面。这个托管堆是在内存中的。而且这个分配对象空间的速度是非常的快的,因为每次都是在托管堆的最后面划出一定的空间来给这个对象,不用去堆上面需找合适大小的空间。
        如果当托管堆准备为一个对象分配空间的时候,发现托管堆上面的空间太小了,不足以分配给这个新的对象,那么CLR 就开始运行垃圾回收机制了。我们知道:垃圾回收机制会把那些在托管堆上面没有了引用指向的那些对象都清理掉,同时也会把托管堆上面现存的对象进行压缩。
        但是有一点需要清楚:如果此时进行了垃圾回收的时候,清除了一些没有用的对象,但是只有在下一次来回收进行的时候,上次垃圾回收清除的对象才真正的从内存中消除( 此时,还有一些“对象复苏“等话题就不在赘述)
 
   下面就来讲述一些垃圾回收的话题。
 
   对象的 代“
CLR 进行垃圾回收的时候,垃圾回收器回去托管堆上面去检查对象是否可以被回收,这个检查过程是非常消耗资源的。为了避免每次垃圾回收都要便利托管堆上面的所有对象,CLR 给把托管堆上面的对象用来划分,例如,第一代,第二代。然后每次便利扫描托管堆的时候,就去扫描某一个中的对象,这样性能就好点。 
在托管堆上面,可以把对象分为三个”:0 代,1 代,2 代,仅此这三个代。每个对象都是从0 代开始的。一个对象每经历一次垃圾回收,并且这个对象还在使用中,那么这个对象的“代“就会增加1 代。例如,如果在0 代的对象,经历了一次垃圾回收之后,他的代就是1 代,如果是1 代的对象,最后就会变为2 代。如果对象本身已经是2 代了,不管经历多少次垃圾回收( 如果对象一直在使用) ,那么这个对象还是2 代。
 
CLR 垃圾回收中有句话要记得:”  ’ 数越大,被回收的可能性就越小。而且一些性能优化就是根据这个进行的。
 
每次CLR 在进行垃圾回收的时候,都会优先的去扫描第0 代的对象,所以,一些新的,临时使用的对象可以被立刻的清除。相比而言,垃圾回收器扫描第1 代对象的频率就没有第0 代强,扫描第2 代对象的频率就更低了。所以说:对象存活的时间越长,就越难被回收,而且一直占据CLR 的内存资源。
 
还有有点需要注意的就是 :如果CLR 决定要扫描了第1 代了,同时也用扫描第0 代的对象,同时如果,CLR 扫描第2 代对象,那么第0 代,第1 代对象都会被扫描。
 
所以,从这里可以得出:我们尽量避免把原本需要立刻回收的的对象变为长期存活的对象。通俗点说就是:如果一个对象本来已经存活在0 代的,然后用完就回收的,我们不要让这个对象一直存活到第1 代,甚至第2 代。在编程上面基本就是这样的实现思路:尽可能晚的实例化对象,尽可能早的释放对象。
 
     大对象堆 (Large Objecet Heap)
我们之前讲述了的一些话题,CLR 除了上面的一般的堆( 一般的new 对象分配空间的那个堆) CLR 中还存在另外的一个堆:专门用来放置那些大于了58k 的对象的堆,大对象堆
如果new 一个对象的时候,这个对象的大小超过了85k ,那么CLR 就会把这个对象放在LOH 上面。如果此时LOH 的空间不足了,那么CLR 就会启动垃圾回收器去扫描LOH 堆和那个一般堆上面的第2 代对象,我们之前说过,如果扫描第2 代对象,就同时扫描第1 代,第0 代,那么实际相当于扫描了整个托管堆,性能影响可想而知。
而且不想之前那个一般堆,在LOH 上面的对象被垃圾回收器回收之后,上面的大对象是不会被压缩的,那么LOH 这个堆上面就可能存在一些空间碎片,然后分配新的大对象的时候,就要找空间,甚至进行碎片的整理,大家可以联想一下我们电脑的磁盘碎片整理。
 
OK ,今天就讲到这里,理论有点多,但是都是基本要清楚和掌握的,希望多多理解。
 
















本文转自yanyangtian51CTO博客,原文链接:  http://blog.51cto.com/yanyangtian/495267 ,如需转载请自行联系原作者











相关文章
|
2月前
|
机器学习/深度学习 存储 PyTorch
PyTorch内存优化的10种策略总结:在有限资源环境下高效训练模型
在大规模深度学习模型训练中,GPU内存容量常成为瓶颈,特别是在训练大型语言模型和视觉Transformer时。本文系统介绍了多种内存优化策略,包括混合精度训练、低精度训练(如BF16)、梯度检查点、梯度累积、张量分片与分布式训练、
90 14
PyTorch内存优化的10种策略总结:在有限资源环境下高效训练模型
|
2月前
|
存储 编解码 安全
阿里云高性能企业级甄选Intel第八代计算型c8i、通用型g8i和内存型r8i实例简介
计算型c8i、通用型g8i和内存型r8i实例是阿里云推出的高性能企业级甄选Intel第八代云服务器实例,采用CIPU+飞天技术架构,搭载最新的Intel 第五代至强可扩展处理器(代号EMR),性能进一步大幅提升,同时拥有AMX加持的AI能力增强,并在全球范围率先支持TDX机密虚拟机能力,实现了AI增强和全面安全防护的两大特色优势。本文将为您介绍这三个实例规格的性能、适用场景及最新活动价格以及选择指南,以供选择参考。
171 18
|
3月前
|
缓存 运维 监控
Anolis OS深度集成运维利器 阿里云操作系统控制台上线
阿里云在百万服务器运维领域的丰富经验打造。
Anolis OS深度集成运维利器 阿里云操作系统控制台上线
|
3月前
|
缓存 运维 监控
追踪隐式资源,巧解内存难题!阿里云操作系统控制台上线
在云计算和容器化部署环境中,云原生容器化已成为行业标准,带来高效部署和成本控制优势的同时,也伴随新的挑战。通过操作系统内存全景功能,可一键扫描诊断,提升运维效率、降低成本,并显著提高系统稳定性。
|
7月前
|
存储 安全 Linux
【开源指南】用二叉树实现高性能共享内存管理
本文介绍了一种使用C++实现的共享内存管理方案,通过借鉴Android property的设计思路,采用二叉树结构存储键值对,提高了数据检索效率。该方案包括设置和获取接口,支持多进程/线程安全,并提供了一个简单的测试示例验证其有效性。
383 36
|
6月前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
6月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
104 5
|
6月前
|
消息中间件 Linux iOS开发
.NET 高性能异步套接字库,支持多协议、跨平台、高并发
【11月更文挑战第3天】本文介绍了高性能异步套接字库在网络编程中的重要性,特别是在处理大量并发连接的应用中。重点讨论了 .NET 中的 Socket.IO 和 SuperSocket 两个库,它们分别在多协议支持、跨平台特性和高并发处理方面表现出色。Socket.IO 基于 WebSocket 协议,支持多种通信协议和跨平台运行,适用于实时通信应用。SuperSocket 则通过事件驱动的异步编程模型,实现了高效的高并发处理,适用于需要自定义协议的场景。这些库各有特点,可根据具体需求选择合适的库。
140 6