带着问题去思考!大家好

相对.NET 来说。CLR去处理了,C,C++这些就需要手动去垃圾回收。

  GC大部分容易察觉的性能问题。其实很多问题实际是哪个都是由于对垃圾回收器的行为和预期结果理解有误。在,NET环境中,你需要更多的关注内存的性能,那么接下里我们主要是讲内存性能问题。

  GC实际上会调整体提高内存堆[1]的性能,因为他能高效的完成内存分配和碎片整理工作。

  在Windows的本机代码模式下,内存堆维护着一张空闲内存块的列表,用于内存的分配,尽量用低碎片化的内存堆,因为长时间运行,还要考虑内存碎片问题,内存占用率会持续增长。所以本机代码程序用大量代码实现了自己的内存分配机制,把默认的malloc函数给替换掉

  在.NET环境中,内存分配的工作量会很小,因为内存总是整段分配的。所以不会比内存的扩大,减小和比较增加多少开销,不存在遍历空闲内存列表,几乎不会出现内存碎片,GC内存堆的效率还会更高的,因为连续分配的多个对象往往在内存堆中也是连续存放,提高就近访问的可能性。

  在默认的内存分配流程中,有一小段代码会先检查目标对象的大小,看看内存分配缓冲区中所剩的内存够不够,如果内存分配缓冲区已耗尽,就会交由GC分配程序来检索足以容纳目标对象的空闲内存。然后一个新的分配缓冲区就会被保留下来。

  接下里看下内存分配的过程

  class MyObject
{
int x;
int y;
int z;
}
static void Main(string[] args)
{
var x = new MyObject();
}

了解汇编语言的都知道这一流程,

MOV指令是数据传送指令,其他的大家可以自行去查约。大致是说,把类的方法表指针拷贝到ecx(计数暂存器)中,作为new ()的参数,调用new,把返回值(对象的地址)拷贝到寄存器中。这里大家大概了解一下就可以了

基本运作方式

在托管进程中存在两种内存堆(本机堆和托管堆),这里我们说下托管堆,本机堆大大家可以自行了解下,

CLR在托管堆(Managed Heap)上为所有的.NET托管对象分配内存,也称之为GC堆,因为其中的对象都要受到垃圾回收机制的控制。

  托管堆又分为两种,小对象堆和大对象堆(LOH),都拥有自己的内存段(Segment[ˈseɡmənt]).内存段的大小视配置和硬件环境而定。

小对象堆

  小对象堆有什么?它又是怎么变化的?

  小对象堆的内存堆分为3代,0,1,2代。第0代和第1代总是位于同一个内存段中,第2代可能跨越多个内存段,LOH也可以跨越多个内存段。包含第0代和第1代堆的内存段被称为暂时段(Ephemeral [ɪˈfemərəl] Segment ˈseɡmənt])

  小对象堆中分配内存的对象生存期。如果 对象小于85000字节,CLR会把它分配在小对象堆中的第0代,通常紧挨当前已用内存空间往后分配,如果扩大内存堆时超越了内存段的边界,则就会触发垃圾回收过程。

  对象总是诞生于第0代内存堆中,只要对象保持存活,每当发生垃圾回收时,GC都会把他提升一代。第0代和第1代内存堆的垃圾回收有时候被称为瞬时回收(Ephemeral Collection)

  在垃圾回收的时候,可能会进行碎片整理(Compaction),也及时GC把对象物理迁移到新的位置中去,以便让内存段中的空闲空间能够连续起来使用。如果为发生碎片整理,那就只需要重新调整各块内存的边界。以下是经历几次未做碎片整理的垃圾回收之后,内存堆的分布可能如下

对象的位置没有移动,但是各代的内存堆的边界发生了变化。

  如果对象到达第2代内存堆,它就会一直留在哪里直至终结。但不代表第2代内存堆只会一直变大, 如果第2代内存堆中的对象都终结了,整个内存段有没有存活[2]的对象,垃圾回收器会把整个内存段交换给操作系统,或者作为其他几代内存堆的附加段,在进行完全垃圾回收(Full Garbge Collection)时,就会可能发生第2代内存堆的回收。

[2]:存活:GC能通过任一已知的GC跟对象(Root),沿着层层引用访问到某个对象,那么它是存活的。GC的根对象可以是程序中的静态变量,或者某个线程的堆栈被正在运行的方法占用(局部变量)或者GC句柄(比如固定对象的句柄,Pinned Handle),或是终结器队列(Finalizer Queue),有些对象可能没有受GC根对象的引用,但如果位于第2代内存堆中,那么第0代回收是不会清理这些对象的。只有完全垃圾回收才会被清理。

  如果第0代堆即将占满一个内存段,垃圾回收也无法通过碎片整理获取足够空闲内存,那么GC会分配一个新的内存段。如图:

  

如果第2代堆继续变大,就可能会跨越多个内存段。LOH也是。但是无论存在多少内存段,第0代和第1代总是位于同一个内存段中。以后我们找出内存堆中有哪些对象存活时。这些会用到。

LOH

LOH,大于85000字节的对象将自动在LOH中分配内存。没有代的概念,垃圾回收期间也不会自动进行碎片化整理,但是可以人为的碎片整理。

垃圾回收的时候会造成什么影响呢?

  垃圾回收是针对某一代及以下几代内存堆进行的。如果回收1代,就会回收0代。如果发生了第0代或第1代垃圾回收,程序在回收期间就会暂停运行,第二代垃圾回收,有部分回收是在后台线程运行进行的。

垃圾回收的4个阶段

  • 挂起(Suspension)---在垃圾回收发生之前,所有托管线程都被强行中止
  • 标记(Mark)--从GC根对象开始,垃圾回收器沿着所有对象引用进行遍历并把所见对象记录下来
  • 碎片整理(Compact)--将对象重新紧挨着存放并更新所有引用,以便减少内存碎片,在小对象堆中,碎片整理会按需进行,无法控制。在LOH中,碎片整理不会自动进行,可以必要时通知垃圾回收器来上一次。
  • 恢复(Resume)--托管线程恢复运行

在标记阶段,不需要遍历内存堆中的所有对象,只要访问那些需要回收的部分即。比如第0代回收只涉及到第0代内存堆中的对象,第1代回收将会标记第0代和第1代内存中的对象。第2代和完全回收,需要遍历内存堆中的所有存活对象,这一开销很大。

  1:垃圾回收过程的耗时几乎完全取决于所涉及的“代”内存堆中的对象数量,而不是你分配到的对象数量,你分配1棵包含100万个对象的树,只要在下次垃圾回收之前把根对象的引用解除。就不会增加垃圾回收的耗时

  2:只要已分配的内存超过某个内部阀值,就会发生这个代垃圾回收,这个阀值是持续变化的。GC会进行调整。

计数器

高性能-GC的更多相关文章

  1. CODE大全告诉你java是否开始没落了

    CODE大全告诉你java是否开始没落了! 22 岁,对于一个技术人来说可谓正当壮年.但对于一门编程语言来说,情况可能又有不同.各类编程语言横空出世,纷战不休,然而 TIOBE 的语言排行榜上,Jav ...

  2. [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少分配率, 最重要的规则,缩短对象的生命周期,减少对象层次的深度,减少对象之间的引用,避免钉住对象(Pinning)

    减少分配率 这个几乎不用解释,减少了内存的使用量,自然就减少GC回收时的压力,同时降低了内存碎片与CPU的使用量.你可以用一些方法来达到这一目的,但它可能会与其它设计相冲突. 你需要在设计对象时仔细检 ...

  3. [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少大对象堆的碎片,在某些情况下强制执行完整GC,按需压缩大对象堆,在GC前收到消息通知,使用弱引用缓存对象

    减少大对象堆的碎片 如果不能完全避免大对象堆的分配,则要尽量避免碎片化. 对于LOH不小心就会有无限增长,但LOH使用的空闲列表机制可以减轻增长的影响.利用这个空闲列表,我们可以在两块分配区域中间找到 ...

  4. [翻译] 编写高性能 .NET 代码--第二章 GC -- 配置选项

    配置选项 在基于"less rope to hang yourself with"思想下,.NET 框架没有给开发提供很多太多的配置选项.但在大多数情况下,GC会跟你的硬件配置,及 ...

  5. [翻译] 编写高性能 .NET 代码--第二章 GC -- 避免使用终结器,避免大对象,避免复制缓冲区

    避免使用终结器 如果没有必要,是不需要实现一个终结器(Finalizer).终结器的代码主要是让GC回收非托管资源用.它会在GC完成标记对象为可回收后,放入一个终结器队列里,在由另外一个线程执行队列里 ...

  6. [翻译] 编写高性能 .NET 代码--第二章 GC -- 将长生命周期对象和大对象池化

    将长生命周期对象和大对象池化 请记住最开始说的原则:对象要么立即回收要么一直存在.它们要么在0代被回收,要么在2代里一直存在.有些对象本质是静态的,生命周期从它们被创建开始,到程序停止才会结束.其它对 ...

  7. C#高性能TCP服务的多种实现方式

    哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...

  8. 使用Ring Buffer构建高性能的文件写入程序

    最近常收到SOD框架的朋友报告的SOD的SQL日志功能报错:文件句柄丢失.经过分析得知,这些朋友使用SOD框架开发了访问量比较大的系统,由于忘记关闭SQL日志功能所以出现了很高频率的日志写入操作,从而 ...

  9. 【腾讯Bugly干货分享】微信mars 的高性能日志模块 xlog

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/581c2c46bef1702a2db3ae53 Dev Club 是一个交流移动 ...

随机推荐

  1. bubble chart|Matrix Scatter|Overlay Scatter|Scatterplots|drop-line|box plot|Stem-and-leaf plot|Histogram|Bar chart|Pareto chart|Pie chart|doughnut chart|

    应用统计学 对类别数据要分类处理: Bar chart复式条形图便于对比: Pareto chart:对类别变量依据频数高低排列: Pie chart:饼图用于一个样本,可以区分类别数据 doughn ...

  2. 谷歌Waymo估值700亿:自动驾驶迎来春天,但前路漫漫

    在经过近一年的法庭之争后,Waymo与Uber的自动驾驶专利权诉讼案于近日宣布和解.最终的结果,是Uber向Waymo支付0.34%股权(目前价值2.44亿美元).但事实上,与Uber的官司解决后,一 ...

  3. The Monster(Codeforce-C-思维题)

    C. The Monster time limit per test 1 second memory limit per test 256 megabytes   As Will is stuck i ...

  4. html解析过程

    Web页面运行在各种各样的浏览器当中,浏览器载入.渲染页面的速度直接影响着用户体验 简单地说,页面渲染就是浏览器将html代码根据CSS定义的规则显示在浏览器窗口中的这个过程.先来大致了解一下浏览器都 ...

  5. c++中的函数重载、函数重写、函数重定义

    目录 一.函数重载 二.函数重写 三.函数重定义 为了更加深刻的理解 函数重载.重写.重定义,我们可以带着如下这两个问题去思考: 1.子类中是否可以定义父类中的同名成员?为什么? 可以,因为子类与父类 ...

  6. 一款属于自己的笔记本【vue+gin+elementUI前后端分离开发部署开源项目】

    前言 我为什么要写一个个人的云笔记? (⊙o⊙)-额额额

  7. 怎么用Python写一个三体的气候模拟程序

    首先声明一下,这个所谓的三体气候模拟程序还是很简单的,没有真的3D效果或数学模型之类的,只不过是一个文字表示的模拟程序.该程序的某些地方可能不太严谨,所以也请各位多多包涵. 所谓三体气候模拟,就是将太 ...

  8. SpringBoot 全局异常处理 @RestControllerAdvice +@ExceptionHandler 请求参数校验

    ControllerAdvice 指示带注释的类辅助“控制器”. 作为的特殊化@Component,允许通过类路径扫描自动检测实现类. 通常用于定义@ExceptionHandler, @InitBi ...

  9. python入门到放弃-基本数据类型之dcit字典

    1.概述 字典是python中唯一的一个映射类型,以{}大括号括起来的键值对组成 字典中的key是唯一的,必须是可hash,不可变的数据类型 语法:{key1:value,key2:value} #扩 ...

  10. vue中的插槽(slot)

    vue中的插槽,指的是子组件中提供给父组件使用的一个占位符,用<slot></slot>标签表示,父组件可以在这个占位符中填充任何模板代码,比如HTML.组件等,填充的内容会替 ...