我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么提高.NET垃圾回收性能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么提高.NET垃圾回收性能

本篇内容介绍了“怎么提高.NET垃圾回收性能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

对于GC垃圾回收,很多人不会陌生。我们这里讲的是提高.NET垃圾回收机制性能的几种方法,通过研究.NET垃圾回收机制,可以提高程序执行效率。

介绍和目标

问一下每一个开发人员,在.Net类中清除非托管资源的***位置在哪里?他们中的70%的人员会说放在析构函数。尽管看起来好象是最有希望的位置,但那对性能和内存消耗有巨大的影响。在析构函数中写清理代码会导致垃圾回收器再次调用,而且多次(multifold times)影响性能。

为了验证上面所说,我们先从理论开始,然后我们会真实的看到使用析构函数时如何影响性能。因此我们要理解世代的概念,然后再去看finalize dispose模式。

我相信本文会改变你关于析构函数、dispose 和 finalize处理的看法。

请随时到 http://www.questpond.com下载我的涵盖.NET、 ASP.NET、 SQLServer、 WCF、 WPF、WWF的免费500个问题和回答的电子书。

假设

本文使用CLR探测器来探测GC如何工作。如果你对CLR探测器不熟悉,在继续之前请先阅读DOTNET1.aspx。

感谢Jeffrey Richter 和 Peter Sollich 先生

让我们以感谢Jeffery Richter作为本文的开始,因为他深入的解释了垃圾回收算法如何工作。他曾经写过两个关于垃圾回收工作方式的传奇文章。我很想指出Jeffery Richter在MSDN杂志写的文章,但因为一些原因并没有在MSDN显示出来。所以我给出一个非官方的地址,你可以从http://www.cs.inf.ethz.ch/ssw/files/GC_in_NET.pdf下载PDF格式文章。

同时也感谢Peter Sollich先生,他是CLR性能框架师,为CLR探测器写了详细的帮助。当你安装CLR探测器时,请不要忘记阅读Peter Sollich写的详细帮助文档。在本文中我们会使用CLR探测器验证使用finalize对垃圾回收器性能的影响。

非常感谢你们的支持,如果没有读你们写的文章,我就不能完成这篇文章,无论何时我都很乐意听到你们阅读文章的评论。

垃圾回收器-幕后英雄

如在介绍中所说,把清理代码放在析构函数会导致垃圾回收器的两次调用。许多开发人员会耸耸肩说“我们真的需要去关心垃圾回收器(GC)在后台做了什么吗?”,对,如果你写合适的代码,我们确实不需要关心垃圾回收。垃圾回收器有保证你的应用程序不受影响的***的算法。但是很多时候,你写代码的方式和在你代码中分配/清理内存资源的方式对垃圾回收算法产生了较大的影响。有时这种影响会导致垃圾回收器(GC)很差的性能,进而导致你应用程序很差的的性能。

因此我们先来看一下在垃圾回收器分配和清理内存时都执行了哪些不同的任务。

假如我们有三个类,类A调用了类B,类B调用了类C。

怎么提高.NET垃圾回收性能

当应用程序***次执行时,预定义内存分配给应用程序。当应用程序创建这3个对象时,它们被赋于一个内存栈上的地址。你可以从下图中看到对象创建之前和对象创建之后的内存的样子。如果还有一个对象D要创建,它会从对象C结束处分配地址。

怎么提高.NET垃圾回收性能

在内部,垃圾回收器为了知道哪些对象是可达的要维护一个对象图。所有的对象属于主应用程序的根对象,根对象同样维护着哪些对象分配了哪些内存地址。如果一个对象使用了其他的对象,那么这个对象也要保存它使用的对象的内存地址。例如,在我们的示例中的对象A使用了对象B,所以对象A保存了对象B的内存地址。

怎么提高.NET垃圾回收性能

现在假如对象A从内存中移除,那么对象A的内存被赋于了对象B,对象B的内存被赋于了对象C。内部的内存分配情况如下所示:

怎么提高.NET垃圾回收性能

随同内存指针的更新,垃圾回收器需要确保它的内部对象图也随着新的内存地址更新了。因此对象图变成了如下所示的样子。对垃圾回收器有一些工作要做,它需要确保已经不再使用的对象已经从图中移除,并且还存在的对象的地址已经在对象树中全部更新了。

怎么提高.NET垃圾回收性能

除应用程序自定义对象外,构成对象图表的还有.Net对象,那些对象的地址也是要更新的。.Net运行时对象的数量非常大,下图就是一个简单的Hello World控制台应用程序创建的对象的数量,对象的数量约有1000个,更新每一个对象的指针是一个很大的任务。

怎么提高.NET垃圾回收性能

世代算法—今天、昨天和前天

GC(垃圾回收器)使用世代的概念来提升性能。世代的概念是基于人们处理事情的心理的方式。下面的几点指出人们是如何处理事情的,并且垃圾回收算法是按相同的方式工作:

如果你今天决定要做一些事情,那么很可能今天就把这些事做完。

如果一些事是昨天未决定的,那么很可能这些事情会给予比较低的优先级并且被再一次推迟。

如果一些事是前天未决定的,那么就有很大的可能性这个事被永远推迟。

GC以同样的方式思考并且使用下面的假设:

如果一个对象是新创建的,那么它的生命期可能很短。

如果一个对象是原来存在的,它可能会有更长的生命。

所以说,GC做了三个世代的支持(0代,1代和2代)。

怎么提高.NET垃圾回收性能

0代包括所有新创建的对象,当应用程序创建对象时,这些对象首先被放入0代对象列表中。当0代对象装满时,GC需要运行以释放内存资源,GC开始构建图表并删除所有应用程序不再使用的对象。如果一个对象GC不能在0代删除,那么该对象会被提升为1代。如果在后面的迭代中一个对象不能在1代中删除,那么它会被提升为2代。.Net运行时支持的***代是2代。

下面是当你运行CLR探测器时关于世代对象的一个简单显示。如果你对CLR探测器不了解,请先从DOTNET1.aspx了解CLR的基本知识。

怎么提高.NET垃圾回收性能

那么,在优化中世代有什么帮助呢

作为世代中的对象,GC会对哪个世代的对象需要被清理做出选择。如果你记得,前面小节中我们讲过关于GC认定对象世代的假设,GC假设新对象具有更短的生命周期。换句话说,GC主要检查0代的对象,而不是所有世代的所有对象。

如果清理0代对象不能提供足够的内存,它将继而清理1代的对象,并依次继续。这个算法能大幅提升GC的性能。

关于世代的推论

如果有大量的对象在1代或2代区域则说明内存使用没有优化。

更大的世代1和世代2区域会导致GC算法性能更差。

使用终结器(finalize)/析构函数会导致更多的1代和2代对象

C#编译器会把析构函数翻译(重命名)为终结器。如果你使用IDASM查看IL代码,就会看到析构函数被重命名为终结器(finalize)。所以让我们先理解为什么实现析构函数会导致更多的对象进入1代和2代区域。现在来看处理器是如何工作的:

当新对象创建时,它们被放到0代。

当0代区域填满时,GC运行并清理内存。

如果对象没有析构函数,那么如果它们不再被使用,GC就把它们清理掉。

如果对象有终结(finalize)方法,GC就把它们放到终结队列中。

如果对象是可达的,它会被放置到Freachable队列中,如果对象是不可达的,内存将被收回。

GC完成本次迭代工作。

下一次当GC开始工作时,它会进入Freachable队列检查对象是否可达,如果Freachable中的对象不可达,内存就会被声名为可收回的。

怎么提高.NET垃圾回收性能

换句话说,有析构函数的对象会在内存中存活更长的时间。

让我们来看下实际的情况,下面是一个简单的有析构函数的类。

class clsMyClass   {     public clsMyClass()
  • {  

  • }  

  • ~clsMyClass()  

  • {  

  • }  

  • }

  • 让我们用CLR探测器来监视创建100*10000个对象时的情况。

    for (int i = 0; i < 100 * 10000; i++)  {   clsMyClass obj = new clsMyClass();
  • }

  • 如果使用CLR探测器的内存地址报表,会看到大量的对象在1代。

    怎么提高.NET垃圾回收性能

    现在去掉析构函数后再做一遍。

    class clsMyClass   {   public clsMyClass()
  • {  

  • }  

  • }

  • 你可以看到在0代对象大量增加,同时1代和2代对象很少。

    怎么提高.NET垃圾回收性能

    如果做一对一的对比,结果如下图所示:

    怎么提高.NET垃圾回收性能

    使用Dispose代替去掉的析构函数

    我们可以去掉析构函数而在dispose方法中实现清理代码。为此要实现‘IDisposable’ 的接口方法,在这写我们的清理代码,并如下代码段所示调用终结方法。

    ‘SuppressFinalize’指示GC不要调用finalize方法,所以不会发生GC的二次调用。

    class clsMyClass : IDisposable  {   public clsMyClass()
  • {  

  • }  

  • ~clsMyClass()  

  • {  

  • }  

  • public void Dispose()  

  • {  

  • GC.SuppressFinalize(this);  

  • }  

  • }

  • 现在客户端要确保它要象如下所示调用

  • dispose

  • 方法。

  • for (int i = 0; i < 100 ; i++)  {  clsMyClass obj = new clsMyClass();
  • obj.Dispose();  

  • }

  • 下图是使用析构函数和使用dispose时的0代和1代对象如何分布的对比。你会看到0代内存分配有明显的提升,这标识着更好的内存分配。

    怎么提高.NET垃圾回收性能

    如果开发人员忘记调用Dispose

    这不是一个***的世界,我们不能确保在客户端总是调用了dispose方法。这就是下面的小节中我们要使用Finalize / Dispose模式的原因。

    关于这个模式在http://msdn.microsoft.com/en-us/library/b1yfkh6e(VS.71).aspx.有详细的实现。

    下面看起来更象是如何实现finalize / dispose模式。

    class clsMyClass : IDisposable  {   public clsMyClass()  {   }   ~clsMyClass()  {  // In case the client forgets to call  // Dispose , destructor will be invoked for  Dispose(false);  }  protected virtual void Dispose(bool disposing)  {  if (disposing)  {  // Free managed objects.  }  // Free unmanaged objects   }   public void Dispose()  {  Dispose(true);  // Ensure that the destructor is not called  GC.SuppressFinalize(this);  }   }

    代码解释:

    我们定义了一个带布尔参数的Dispose方法,该参数说明是从Dispose中调用还是从析构函数中调用。如果是从’Dispose’方法调用,则释放所有的托管和非托管的资源。

    如果该方法是从析构函数中调用,则只释放非托管的资源。

    在dispose方法中我们禁用了finilize的调用,并且用true参数调用了这个dispose方法。

    在析构函数中我们使用false值调用dispose函数。换句话说,我们假定GC会处理好托管的资源并用析构函数调用来清理非托管资源。

    换句话说,客户端没有调用dispose函数,析构函数会照顾清除非托管资源。

“怎么提高.NET垃圾回收性能”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么提高.NET垃圾回收性能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么提高.NET垃圾回收性能

本篇内容介绍了“怎么提高.NET垃圾回收性能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!对于GC垃圾回收,很多人不会陌生。我们这里讲的是提
2023-06-17

.NET垃圾回收器怎么使用

这篇文章主要介绍了.NET垃圾回收器怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇.NET垃圾回收器怎么使用文章都会有所收获,下面我们一起来看看吧。.NET 应用程序中的垃圾回收器是什么?垃圾收集器只不
2023-06-29

通过Go语言的垃圾回收机制,提高性能和内存效率

Go语言的垃圾回收机制可以帮助开发人员提高性能和内存效率。垃圾回收是自动管理内存的过程,它可以自动检测和清理不再使用的内存,从而避免内存泄漏和垃圾堆积。以下是通过Go语言的垃圾回收机制提高性能和内存效率的一些方法:1. 自动内存管理:Go语
2023-10-08

在Go语言中实现高性能的垃圾回收器管理

在Go语言中,垃圾回收是由运行时系统自动管理的,不需要手动管理内存。Go语言的垃圾回收器采用了并发标记清除算法和三色标记法,以实现高性能的垃圾回收。并发标记清除算法:在垃圾回收开始前,运行时系统会中断所有的Go程,并从根对象(全局变量、活跃
2023-10-08

Java中的垃圾回收机制是如何工作的?如何优化Java的垃圾回收?(Java的垃圾回收器如何运作?有哪些策略可以优化Java的垃圾回收性能?)

Java垃圾回收机制通过根引用扫描、图遍历、标记和清除过程回收不再使用的对象。优化策略包括减少对象分配、使用大对象、避免循环引用、调整GC参数和使用最新JVM版本。监控GC性能并根据特定需求优化策略至关重要。
Java中的垃圾回收机制是如何工作的?如何优化Java的垃圾回收?(Java的垃圾回收器如何运作?有哪些策略可以优化Java的垃圾回收性能?)
2024-04-02

JavaScript中垃圾回收怎么优化

这篇文章将为大家详细讲解有关JavaScript中垃圾回收怎么优化,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、循环中的函数表现式,最好再利用。// 在循环中最好也别使用函数表达式。for (var
2023-06-15

Java的垃圾回收怎么理解

这篇“Java的垃圾回收怎么理解”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java的垃圾回收怎么理解”文章吧。在说记忆集
2023-06-29

怎么理解Java 垃圾回收机制

怎么理解Java 垃圾回收机制,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。什么是自动垃圾回收自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将
2023-06-05

C#垃圾回收问题怎么解决

本篇内容主要讲解“C#垃圾回收问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#垃圾回收问题怎么解决”吧!这里涉及到C#垃圾回收的问题:C#垃圾回收是.NET运行库的一部分。垃圾回收
2023-06-17

怎么理解JavaScript垃圾回收机制

本篇内容介绍了“怎么理解JavaScript垃圾回收机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!机制说明1、找出不再使用的变量,然后释
2023-06-25

java垃圾回收算法怎么应用

Java中的垃圾回收算法是通过自动内存管理实现的,开发人员不需要手动去释放内存。Java中的垃圾回收算法主要有以下几种:1. 引用计数法(Reference Counting):每个对象都有一个引用计数器,当有引用指向该对象时计数器加1,引
2023-10-08

Golang中的垃圾回收怎么处理

Golang中的垃圾回收是自动进行的,并且采用了一个标记-清除算法。当程序运行时,垃圾回收器会定期检查堆中的对象,并标记那些仍然被引用的对象。然后,它会清除那些未被标记的对象,释放它们所占用的内存空间。Golang的垃圾回收器是并发的,意
Golang中的垃圾回收怎么处理
2024-03-13

Go与Rust之间的垃圾回收性能和类别

小伙伴们对Golang编程感兴趣吗?是否正在学习相关知识点?如果是,那么本文《Go与Rust之间的垃圾回收性能和类别》,就很适合你,本篇文章讲解的知识点主要包括。在之后的文章中也会多多分享相关知识点,希望对大家的知识积累有所帮助!问题内容我
Go与Rust之间的垃圾回收性能和类别
2024-04-04

Python垃圾回收机制怎么掌握

这篇文章主要介绍“Python垃圾回收机制怎么掌握”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python垃圾回收机制怎么掌握”文章能帮助大家解决问题。得益于 Python 的自动垃圾回收机制,在
2023-07-05

golang垃圾回收算法怎么实现

Go语言的垃圾回收(Garbage Collection)是由Go语言的运行时系统(runtime system)自动进行的,开发者无需手动实现。Go语言的垃圾回收算法使用了三色标记(tricolor marking)算法,具体实现如下:
2023-10-23

怎么理解Python中的垃圾回收

这篇文章主要介绍“怎么理解Python中的垃圾回收”,在日常操作中,相信很多人在怎么理解Python中的垃圾回收问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么理解Python中的垃圾回收”的疑惑有所帮助!
2023-06-16

Java垃圾回收机制怎么理解

这篇文章主要讲解了“Java垃圾回收机制怎么理解”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java垃圾回收机制怎么理解”吧!Java垃圾回收是一个自动运行的管理程序运行时使用的内存的进程
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录