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

简介: 原文:【原创】构建高性能ASP.NET站点 第七章 如何解决内存的问题(前篇)—托管资源优化—垃圾回收机制深度剖析构建高性能ASP.NET站点 第七章 如何解决内存的问题(前篇)—托管资源优化—垃圾回收机制剖析     前言:本章主要详细的讲述如何因内存问题而导致的性能问题,很多的时候都是深入.NET内核进行分析,然后给出解决方案,同时,本系列的其他文章,也争取做到:深入浅出。
原文: 【原创】构建高性能ASP.NET站点 第七章 如何解决内存的问题(前篇)—托管资源优化—垃圾回收机制深度剖析

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

    前言:本章主要详细的讲述如何因内存问题而导致的性能问题,很多的时候都是深入.NET内核进行分析,然后给出解决方案,同时,本系列的其他文章,也争取做到:深入浅出。

 

   本篇是为后面的做个铺垫,而且比较的精彩。只有真正的理解了本篇,后面才可以顺利的走下去。

 

本篇的议题如下:

内存问题概述(前篇)

托管资源优化(前篇)

         对象的生命周期(前篇)

         对象的代“(前篇)

         大对象堆(LOH) (前篇)

         CLR计数器的使用         (前篇)

         CLR Profiler的使用(中篇)

         垃圾回收器的不同版本(中篇)

         对象使用注意事项(中篇)

         常用优化措施(后篇)

非托管资源优化

Session会话的优化

 

  系列文章链接:

  构建高性能ASP.NET站点 开篇

  构建高性能ASP.NET站点之一 剖析页面的处理过程(前端)

  构建高性能ASP.NET站点之二 优化HTTP请求(前端)

  构建高性能ASP.NET站点之三 细节决定成败

  构建高性能ASP.NET站点 第五章—性能调优综述(前篇)

  大型高性能ASP.NET系统架构设计  

  构建高性能ASP.NET站点 第五章—性能调优综述(中篇)

  构建高性能ASP.NET站点 第五章—性能调优综述(后篇)

  构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(上篇)—识别性能瓶颈

  构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下前篇)—简单的优化措施

  构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下后篇)—减少不必要的请求

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

  构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测CLR性能

 

 

   内存问题概述

    和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中还存在另外的一个堆:专门用来放置那些大于了85k的对象的堆,大对象堆

如果new一个对象的时候,这个对象的大小超过了85k,那么CLR就会把这个对象放在LOH上面。如果此时LOH的空间不足了,那么CLR就会启动垃圾回收器去扫描LOH堆和那个一般堆上面的第2代对象,我们之前说过,如果扫描第2代对象,就同时扫描第1代,第0代,那么实际相当于扫描了整个托管堆,性能影响可想而知。

而且不想之前那个一般堆,在LOH上面的对象被垃圾回收器回收之后,上面的大对象是不会被压缩的,那么LOH这个堆上面就可能存在一些空间碎片,然后分配新的大对象的时候,就要找空间,甚至进行碎片的整理,大家可以联想一下我们电脑的磁盘碎片整理。

 

OK,今天就讲到这里,理论有点多,但是都是基本要清楚和掌握的,希望多多理解。

 

        

目录
相关文章
|
2月前
|
存储 Shell Linux
快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
本文介绍了如何使用脚本自动化构建 `.net` 应用的 `nuget` 包并推送到指定服务仓库。首先概述了 `BaGet`——一个开源、轻量级且高性能的 `NuGet` 服务器,支持多种存储后端及配置选项。接着详细描述了 `BaGet` 的安装、配置及使用方法,并提供了 `PowerShell` 和 `Bash` 脚本实例,用于自动化推送 `.nupkg` 文件。最后总结了 `BaGet` 的优势及其在实际部署中的便捷性。
126 10
|
10天前
|
Kubernetes Cloud Native Ubuntu
庆祝 .NET 9 正式版发布与 Dapr 从 CNCF 毕业:构建高效云原生应用的最佳实践
2024年11月13日,.NET 9 正式版发布,Dapr 从 CNCF 毕业,标志着云原生技术的成熟。本文介绍如何使用 .NET 9 Aspire、Dapr 1.14.4、Kubernetes 1.31.0/Containerd 1.7.14、Ubuntu Server 24.04 LTS 和 Podman 5.3.0-rc3 构建高效、可靠的云原生应用。涵盖环境准备、应用开发、Dapr 集成、容器化和 Kubernetes 部署等内容。
35 5
|
25天前
|
机器学习/深度学习 算法 物联网
大模型进阶微调篇(一):以定制化3B模型为例,各种微调方法对比-选LoRA还是PPO,所需显存内存资源为多少?
本文介绍了两种大模型微调方法——LoRA(低秩适应)和PPO(近端策略优化)。LoRA通过引入低秩矩阵微调部分权重,适合资源受限环境,具有资源节省和训练速度快的优势,适用于监督学习和简单交互场景。PPO基于策略优化,适合需要用户交互反馈的场景,能够适应复杂反馈并动态调整策略,适用于强化学习和复杂用户交互。文章还对比了两者的资源消耗和适用数据规模,帮助读者根据具体需求选择最合适的微调策略。
|
1月前
|
数据库连接 开发者
.NET 内存管理两种有效的资源释放方式
【10月更文挑战第15天】在.NET中,有两种有效的资源释放方式:一是使用`using`语句,适用于实现`IDisposable`接口的对象,如文件流、数据库连接等,能确保资源及时释放,避免泄漏;二是手动调用`Dispose`方法并处理异常,提供更灵活的资源管理方式,适用于复杂场景。这两种方式都能有效管理资源,提高应用性能和稳定性。
|
1月前
|
算法 Java 数据库连接
.NET 内存管理两种有效的资源释放方式
【10月更文挑战第14天】在 .NET 中,`IDisposable` 接口提供了一种标准机制来释放非托管资源,如文件句柄、数据库连接等。此类资源需手动释放以避免泄漏。实现 `IDisposable` 的类可通过 `Dispose` 方法释放资源。使用 `using` 语句可确保资源自动释放。此外,.NET 的垃圾回收器会自动回收托管对象所占内存,提高程序效率。示例代码展示了如何使用 `MyFileHandler` 类处理文件操作并释放 `FileStream` 资源。
|
2月前
|
缓存 Java 测试技术
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
使用JMeter对项目各个接口进行压力测试,并对前端进行动静分离优化,优化三级分类查询接口的性能
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
|
3月前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
166 0
|
3月前
|
Java Spring 自然语言处理
Spring 框架里竟藏着神秘魔法?国际化与本地化的奇妙之旅等你来揭开谜底!
【8月更文挑战第31天】在软件开发中,国际化(I18N)与本地化(L10N)对于满足不同地区用户需求至关重要。Spring框架提供了强大支持,利用资源文件和`MessageSource`实现多语言文本管理。通过配置日期格式和货币符号,进一步完善本地化功能。合理应用这些特性,可显著提升应用的多地区适应性和用户体验。
40 0
|
3月前
|
微服务 API Java
微服务架构大揭秘!Play Framework如何助力构建松耦合系统?一场技术革命即将上演!
【8月更文挑战第31天】互联网技术飞速发展,微服务架构成为企业级应用主流。微服务将单一应用拆分成多个小服务,通过轻量级通信机制交互。高性能Java Web框架Play Framework具备轻量级、易扩展特性,适合构建微服务。本文探讨使用Play Framework构建松耦合微服务系统的方法。Play采用响应式编程模型,支持模块化开发,提供丰富生态系统,便于快速构建功能完善的微服务。
49 0
|
3月前
|
SQL 开发框架 .NET
代码更简洁,开发更高效:从零开始使用Entity Framework Core与传统ADO.NET构建数据持久化层的比较
【8月更文挑战第31天】在.NET平台上开发数据驱动应用时,选择合适的ORM框架至关重要。本文通过对比传统的ADO.NET和现代的Entity Framework Core (EF Core),展示了如何从零开始构建数据持久化层。ADO.NET虽强大灵活,但需要大量手写代码;EF Core则简化了数据访问,支持LINQ查询,自动生成SQL命令,提升开发效率。从创建.NET Core项目、定义数据模型、配置`DbContext`到执行数据库操作,EF Core提供了一套流畅的API,使数据持久化层的构建变得简单直接。
38 0