深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第六节 理解垃圾回收GC,提搞程序性能

news2025/1/15 23:33:41

深入浅出图解C#堆与栈 C# Heaping VS Stacking 第六节 理解垃圾回收GC,提搞程序性能

  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第一节 理解堆与栈](https://mp.csdn.net/mdeditor/101021023)
  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节 栈基本工作原理](https://mp.csdn.net/mdeditor/101022949#)
  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第三节 栈与堆,值类型与引用类型](https://mp.csdn.net/mdeditor/101023885#)
  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1](https://mp.csdn.net/mdeditor/101026168#)
  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 2](https://mp.csdn.net/mdeditor/101027584#)
  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复](https://mp.csdn.net/mdeditor/101028008#)
  • [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第六节 理解垃圾回收GC,提搞程序性能](https://mp.csdn.net/mdeditor/101029557#)
  • 理解垃圾回收GC,提搞程序性能
    • 前言
    • 简介
    • 绘图Graphing
    • GC垃圾清理Compacting
    • 托管堆之外的终止化队列Finalization Queue和终止化-可达队列Freachable Queue
    • 静态变量
    • 总结

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第一节 理解堆与栈

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节 栈基本工作原理

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第三节 栈与堆,值类型与引用类型

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 2

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第六节 理解垃圾回收GC,提搞程序性能

理解垃圾回收GC,提搞程序性能

前言

虽然在.Net Framework 中我们不必考虑内在管理和垃圾回收(GC),但是为了优化应用程序性能我们始终需要了解内存管理和垃圾回收(GC)。另外,了解内存管理可以帮助我们理解在每一个程序中定义的每一个变量是怎样工作的。


简介

这一节我们将介绍垃圾回收机制GC以及一些提搞程序性能的技巧。


绘图Graphing

让我们站在GC的角度研究一下。如果我们负责“扔垃圾”,我们需要制定一个有效的“扔垃圾”计划。显然,我们需要判断哪些是垃圾,哪些不是。

为了决定哪些需要保留,我们假设任何没有正在被使用的东西都是垃圾(如角落里堆积的破旧纸张,阁楼里一箱箱没有用的过时产品,柜子里不用的衣服)。想像一下我们跟两个好朋友生活在一起:JIT 和CLR。JIT和CLR不断的跟踪他们正在使用的东西,并给我们一个他们需要保留的东西列表。这个初始列表我们叫它“根(root)”列表。因为我们用它做起点。我们将保持一个主列表去绘制一张图,图中分布着所有我们在房子中需要保留东西。任何与主列表中有关联的东西也被画入图中。如,我们保留电视就不要扔掉电视遥控器,所以电视遥控器也会被画入图中。我们保留电脑就不能扔掉显示器键盘鼠标,同样也把它们画入图中。

这就是GC怎么决定去保留对象的。GC会保留从JIT和CLR那收到的一个根(root)对象引用列表,然后递归搜索对象引用并决定什么需要保留。

这个根的构成如下:

  • 全局/静态 指针。通过以静态变量的方式保持对象的引用,来确保对象不会被GC回收。
  • 栈里的指针。为了程序的执行,我们不想扔掉那些程序线程始终需要的对象。
  • CPU寄存器指针。托管堆里任何被CPU内存地址指向的对象都需要被保留。

在这里插入图片描述
在上面的图中,托管堆中的对象1,5被根Roots引用,3被1引用。对象1,5是被直接引用,3是通过递归查询找到。如果关联到我们之前的假设,对象1是我们的电视,对象3则是电视遥控器。当所有对象画完后,我们开始进行下一阶段:垃圾清理。

GC垃圾清理Compacting

现在我们有了一张需要保留对象的关系图,接下来进行GC的清理。
在这里插入图片描述
图中对象2和4被认定为垃圾将被清理。清理对象2,复制(memcpy )对象3到2的位置。
在这里插入图片描述
由于对象3的地址变了,GC需要修复指针(红色箭头)。然后清理对象4,复制(memcpy )对象5到原来3的位置(译外话:GC原则:堆中对象之间是没有间隙的,以后会有文章专门介绍GC原理)。
在这里插入图片描述
在这里插入图片描述
最后清理完毕,新对象将被放到对象5的上面(译外话:GC对一直管理一个指针指向新对象将被放置的地址,如黄色箭头,以后会有文章专门介绍)。

了解GC原理可以帮助我们理解GC清理(复制memcpy ,指针修复等)是怎么消耗掉很多资源的。很明显,减少托管堆里对象的移动(复制memcpy )可以提高GC清理的效率。

托管堆之外的终止化队列Finalization Queue和终止化-可达队列Freachable Queue

有些情况下,GC需要执行特定代码去清理非托管资源,如文件操作,数据库连接,网络连接等。一种可行性方案是使用析构函数(终结器):
在这里插入图片描述
译外话:析构函数会被内部转换成终结器override Finializer()

有终结器的对象在创建时,同时在Finalization Queue里创建指向它们的指针(更正原文说的把对象放到Finalization Queue里):

在这里插入图片描述
上图对象1,4,5实现了终结器,因此在Finalization Queue里创建指向它们的指针。让我们看一下,当对象2和4没有被程序引用要被GC清理时会发生什么情况。
对象2会被以常规模式清理掉(见文章开始部分)。GC发现对象4有终结器,则会把Finalization Queue里指向它的指针移到Freachable Queue中,如下图:
在这里插入图片描述
但是对象4并不被清理掉。有一个专门处理Freachable Queue的线程,当它处理完对象4在Freachable Queue里的指针后,会把它移除。

在这里插入图片描述
这时对象4可以被清理了。当下次GC清理时会把它移除掉。换句话说,至少执行两次GC清理才能把对象4清理掉,显然会影响程序性能。

创建终结器,意味着创建了更多的工作给GC,也就会消耗更多资源影响程序性能。因此,当你使用终结器时一定要确保你确实需要使用它。
更好的方法是使用IDisposable接口。

在这里插入图片描述
实现IDisposable接口的对象可以使用using关键字:
在这里插入图片描述
变量rec的作用域是大括号内,大括号外不可访问。

静态变量

在这里插入图片描述

如果你初始化了TryoutRunners,那么它将永远不会被GC清理,因为有静态指针一直指向初始化的对象。一旦调用了Runner里GetStats()方法,因为GetStats()里面没有文件关闭操作,它将永远被打开也不会被GC清理。我们可以看到程序的崩溃即将来临。

总结

一些良好的操作可以提高程序的性能:

1.清理。不要打开资源而不关闭它。关闭所有你打开的连接。尽可能快的清理所有非托管资源。一般规则:使用非托管对象,初始化越晚越好,清理越早越好。
2.不要过度引用。合理使用引用对象。如果某一个对象还存在没有被GC清理,所有它引用的对象都将不会被GC清理,如此递归下去。。。当我们完成使用一个引用对象时,把它设为NULL(视你的情况而定,注意不要产生空引用异常)。当引用少了,GC开始创建清理关系图graphing时过程就简单一些了,进而提高程序性能。
3.谨慎使用终结器Finalizaer或析构函数。能使用IDisposible代替就使用IDisposible。
4.保持对象及其成员的紧凑。如果声明一个对象并且它由多个子对象组成,尽可能的把它们放在一起初始化,好让它们所在的内存空间紧凑。GC复制这样的一大块内存比复制分散的内存碎片要容易。

原文连接:https://blog.csdn.net/leewhoee/article/details/17109201
译文连接:http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory_401282006141834PM/csharp_memory_4.aspx

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1340772.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu fcitx Install

ubuntu经常出现键盘失灵的问题 查询资料得知应该是Ibus框架的问题 于是需要安装fcitx框架和搜狗拼音 sudo apt update sudo apt install fcitx 设置fcitx开机自启动(建议) sudo cp /usr/share/applications/fcitx.desktop /etc/xdg/autostart/ 然后…

2024-软件测试工程师面试题,面试前一天刷效果更佳。

bug的定义,bug的周期 软件bug是指软件程序的漏洞和缺陷,测试工程师或用户所发现和提出的软件可改进的细节、或与需求文档存在差异的功能实现等生命周期中缺陷状态:新建-->指派-->已解决-->待验-->关闭 发现BUG-->提交BUG--&g…

案例260:基于微信小程序的签到系统的设计与实现

文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder …

重磅发布|博睿数据2023年度精选案例集—— IT运维之光

当前,数字经济已经成为全球经济增长的重要引擎。随着新技术的飞速发展,企业数字化转型机遇不断涌现,而稳定、安全、可靠的IT运维环境是实现数字化转型的关键。 在此背景下,AIOps 智能运维正成为企业高效管控种类繁多数量庞大的物…

听说!Art-DAQ实现了与LabVIEW的无缝连接

前言 阿尔泰科技与时俱进,推出Art-DAQ程序,与LabVIEW无缝连接,形成系统平台体系。持续不断地获取行业新技术,完善自主知识产权产品的研发,为客户提供优质服务。 什么是Labview? 从产品的角度来看&#x…

电话号码的字母组合[中等]

一、题目 给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意1不对应任何字母。 示例 1: 输入:digits "23" 输出&am…

java itext5 生成PDF并填充数据导出

java itext5 生成PDF并填充数据导出 依赖**文本勾选框****页眉**&#xff0c;**页脚****图片**实际图 主要功能有文本勾选框&#xff0c;页眉&#xff0c;页脚&#xff0c;图片等功能。肯定没有专业软件画的好看&#xff0c;只是一点儿方法。仅供参考。 依赖 <!--pdf-->&…

CAS-手写自旋锁

CAS与自旋锁&#xff0c;借鉴CAS思想 什么是自旋锁&#xff1f; CAS是实现自旋锁的基础&#xff0c;CAS利用CPU指令保证了操作的原子性&#xff0c;以达到锁的效果&#xff0c;至于自旋 锁---字面意思自己旋转。是指尝试获取锁的线程不会立即阻塞&#xff0c;而是采用循环的…

【头歌实训】kafka-入门篇

文章目录 第1关&#xff1a;kafka - 初体验任务描述相关知识Kafka 简述Kafka 应用场景Kafka 架构组件kafka 常用命令 编程要求测试说明答案代码 第2关&#xff1a;生产者 &#xff08;Producer &#xff09; - 简单模式任务描述相关知识Producer 简单模式Producer 的开发步骤Ka…

庙算兵棋推演AI开发初探(2-编写策略(上))

开始研读step()函数的编写方法。 这个是图灵网提供了一些基础的ai代码下载&#xff08;浏览需要注册&#xff0c;下载需要审批&#xff09;。 AI开发中心-人机对抗智能 (ia.ac.cn)http://turingai.ia.ac.cn/ai_center/show 一、代码研读(BaseAgent类) 1.step函数 这段代码定…

快速上手makefile自动化构建工具

makefile自动化构建工具 文章目录 makefile自动化构建工具 makefile背景 简单认识makefile 依赖关系与依赖方法 生成项目 清理项目 ACM时间 语法补充 .PHONY修饰 特殊符号替换 Makefile的推导过程 总结 前言&#xff1a; 在windows下&#xff0c;很多东西都是编译器直接帮你做…

Java EasyExcel 导入代码

Java EasyExcel 导入代码 导入方法 /*** 仓库库位导入** param req* param res* param files* throws Exception*/RequestMapping(value {"/import/line_store_locs"}, method {RequestMethod.POST})ResponseBodypublic void importStoreLoc(HttpServletRequest …

关于Redis面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv Redis 是什么 全名&#xff1a;远程字典服务。这是一个开源的在内存中的数据结构存…

中职网络安全Web2003-2——Web渗透测试

需要环境或换&#xff0c;有问题可以私信我或加Q 1.通过URL访问http://靶机IP/1&#xff0c;对该页面进行渗透测试&#xff0c;将完成后返回的结果内容作为Flag值提交&#xff1b; FLAGflag{htmlcode} 2.通过URL访问http://靶机IP/2&#xff0c;对该页面进行渗透测试&#xff…

设计模式(4)--对象行为(6)--备忘录

1. 意图 在不破坏封装的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态。 这样以后可以将该对象恢复到原先保存的状态。 2. 三种角色 原发器(Originator)、备忘录(Memento)、负责人(Caretaker) 3. 优点 3.1 保持了封装边界。屏蔽了原发器的…

汇编语言学习中的Dosbox自动配置方法

学到期末才发现可以自动配置 一、先找到dosbox的下载/安装路径 二、打开其下的Dosbox *.**(这里是版本号) Options.bat 三、在其打开的文件的最下面输入你经常打开dosbox要输入的内容 例如&#xff1a; mount c e:\masm c:

C++day3作业

#include <iostream>using namespace std;class Person {int *age;string &name; public: // Person() // {// }Person(int a,string &b):age(new int(a)),name(b){cout << "Person的有参构造" << endl;}Person(const Person &am…

关于设计模式、Java基础面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv 设计模式 单例共有几种写法&#xff1f; 细分起来就有9种&#xff1a;懒汉&#x…

信号与线性系统翻转课堂笔记15——离散LTI系统模型分析

信号与线性系统翻转课堂笔记15——离散LTI系统模型分析 The Flipped Classroom15 of Signals and Linear Systems 对应教材&#xff1a;《信号与线性系统分析&#xff08;第五版&#xff09;》高等教育出版社&#xff0c;吴大正著 一、要点 &#xff08;1&#xff0c;重点&…

Java 基础学习(十八)多线程进阶、网络编程基础

1 并发工具包 1.1 并发工具包概述 1.1.1 什么是并发工具包 Java并发工具包是指java.util.concurrent&#xff08;简称JUC&#xff09;&#xff0c;在Java 5 版本中添加。JUC中包含了大量在并发应用开发中非常实用的工具类。 行业中说的JUC一般包含java.util.concurrent包、…