GC roots

1.虚拟机栈(本地变量表)引用的对象html

2.方法区静态属性引用的对象
3.方法区常量引用的对象
4.本地方法栈JNI(通常指naive方法)中引用的对象
 

常说的GC(Garbage Collector) roots,特指的是垃圾收集器(Garbage Collector)的对象,GC会收集那些不是GC roots且没有被GC roots引用的对象。java

一个对象能够属于多个root,GC root有几下种:算法


  • Class - 由系统类加载器(system class loader)加载的对象,这些类是不可以被回收的,他们能够以静态字段的方式保存持有其它对象。咱们须要注意的一点就是,经过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,不然它们并非roots,.
  • Thread - 活着的线程
  • Stack Local - Java方法的local变量或参数
  • JNI Local - JNI方法的local变量或参数
  • JNI Global - 全局JNI引用
  • Monitor Used - 用于同步的监控对象
  • Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并无为这些对象提供其它的信息,所以就只有留给分析分员去肯定哪些是属于"JVM持有"的了。

如下是一张由Java Profiler的标示出哪些是GC roots的示例图:bootstrap

 

做者:RednaxelaFX
连接:https://www.zhihu.com/question/53613423/answer/135743258
来源:知乎
著做权归做者全部,转载请联系做者得到受权。数据结构

 

以前看深刻理解JVM这本书,对里面的GC ROOT的真实含义不是太清楚,网上查了一大堆资料都没有说的很清楚,下面这是从知乎大神上看到的,这里面记录一下,和你们一块儿学习并发

 

所谓“GC roots”,或者说tracing GC的“根集合”,就是一组必须活跃的引用。
例如说,这些引用可能包括:
  • 全部Java线程当前活跃的栈帧里指向GC堆里的对象的引用;换句话说,当前全部正在被调用的方法的引用类型的参数/局部变量/临时值。
  • VM的一些静态数据结构里指向GC堆里的对象的引用,例如说HotSpot VM里的Universe里有不少这样的引用。
  • JNI handles,包括global handles和local handles
  • (看状况)全部当前被加载的Java类
  • (看状况)Java类的引用类型静态变量
  • (看状况)Java类的运行时常量池里的引用类型常量(String或Class类型)
  • (看状况)String常量池(StringTable)里的引用
注意,是一组必须活跃的引用,不是对象。

Tracing GC的根本思路就是:给定一个集合的引用做为根出发,经过引用关系遍历对象图,能被遍历到的(可到达的)对象就被断定为存活,其他对象(也就是没有被遍历到的)就天然被断定为死亡。注意再注意:tracing GC的本质是经过找出全部活对象来把其他空间认定为“无用”,而不是找出全部死掉的对象并回收它们占用的空间。
GC roots这组引用是tracing GC的起点。要实现语义正确的tracing GC,就必需要能完整枚举出全部的GC roots,不然就可能会漏扫描应该存活的对象,致使GC错误回收了这些被漏扫的活对象。

这就像任何递归定义的关系同样,若是只定义了递推项而不定义初始项的话,关系就没法成立——无从开始;而若是初始项定义漏了内容的话,递推出去也会漏内容。

那么分代式GC对GC roots的定义有什么影响呢?
答案是:分代式GC是一种部分收集(partial collection)的作法。在执行部分收集时,从GC堆的非收集部分指向收集部分的引用,也必须做为GC roots的一部分。
具体到分两代的分代式GC来讲,若是第0代叫作young gen,第1代叫作old gen,那么若是有minor GC / young GC只收集young gen里的垃圾,则young gen属于“收集部分”,而old gen属于“非收集部分”,那么从old gen指向young gen的引用就必须做为minor GC / young GC的GC roots的一部分。
继续具体到HotSpot VM里的分两代式GC来讲,除了old gen到young gen的引用以外,有些带有弱引用语义的结构,例如说记录全部当前被加载的类的SystemDictionary、记录字符串常量引用的StringTable等,在young GC时必需要做为strong GC roots,而在收集整堆的full GC时则不会被看做strong GC roots。

换句话说,young GC比full GC的GC roots还要更大一些。若是不能理解这个道理,那整个讨论也就无从谈起了。
 
复制代码
Garbage Collection Roots
A garbage collection root is an object that is accessible from outside the heap. The following reasons make an object a GC root:
System Class
Class loaded by bootstrap/system class loader. For example, everything from the rt.jar like java.util.* .
JNI Local
Local variable in native code, such as user defined JNI code or JVM internal code.
JNI Global
Global variable in native code, such as user defined JNI code or JVM internal code.
Thread Block
Object referred to from a currently active thread block.
Thread
A started, but not stopped, thread.
Busy Monitor
Everything that has called wait() or notify() or that is synchronized. For example, by calling synchronized(Object) or by entering a synchronized method. Static method means class, non-static method means object.
Java Local
Local variable. For example, input parameters or locally created objects of methods that are still in the stack of a thread.
Native Stack
In or out parameters in native code, such as user defined JNI code or JVM internal code. This is often the case as many methods have native parts and the objects handled as method parameters become GC roots. For example, parameters used for file/network I/O methods or reflection.
Finalizable
An object which is in a queue awaiting its finalizer to be run.
Unfinalized
An object which has a finalize method, but has not been finalized and is not yet on the finalizer queue.
Unreachable
An object which is unreachable from any other root, but has been marked as a root by MAT to retain objects which otherwise would not be included in the analysis.
Java Stack Frame
A Java stack frame, holding local variables. Only generated when the dump is parsed with the preference set to treat Java stack frames as objects.
Unknown
An object of unknown root type. Some dumps, such as IBM Portable Heap Dump files, do not have root information. For these dumps the MAT parser marks objects which are have no inbound references or are unreachable from any other root as roots of this type. This ensures that MAT retains all the objects in the dump

做者:秦汉邮侠
连接:https://www.jianshu.com/p/f4ff9fcc0759
來源:简书
简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。
复制代码

 

 

参考:less

https://www.jianshu.com/p/f4ff9fcc0759jvm

 

原文地址:https://www.cnblogs.com/FlyAway2013/p/10240919.html

题主对“GC roots”的概念的理解彻底错误
若是题主是把“GC roots”(根引用集合)实质上理解成了“live set”(存活的对象的集合)的概念的话,这就好理解了。不然很难理解题主想说的是什么意思。ide

=================================================post

题主说:
个人理解是jvm不可能把GC roots找全乎了,把全部的gc root所有找出来也能够可是效率过低

所谓“GC roots”,或者说tracing GC的“根集合”,就是一组必须活跃的引用
例如说,这些引用可能包括:
  • 全部Java线程当前活跃的栈帧里指向GC堆里的对象的引用;换句话说,当前全部正在被调用的方法的引用类型的参数/局部变量/临时值。
  • VM的一些静态数据结构里指向GC堆里的对象的引用,例如说HotSpot VM里的Universe里有不少这样的引用。
  • JNI handles,包括global handles和local handles
  • (看状况)全部当前被加载的Java类
  • (看状况)Java类的引用类型静态变量
  • (看状况)Java类的运行时常量池里的引用类型常量(String或Class类型)
  • (看状况)String常量池(StringTable)里的引用

注意,是一组必须活跃的引用,不是对象。

Tracing GC的根本思路就是:给定一个集合的引用做为根出发,经过引用关系遍历对象图,能被遍历到的(可到达的)对象就被断定为存活,其他对象(也就是没有被遍历到的)就天然被断定为死亡。注意再注意:tracing GC的本质是经过找出全部活对象来把其他空间认定为“无用”,而不是找出全部死掉的对象并回收它们占用的空间。
GC roots这组引用是tracing GC的起点。要实现语义正确的tracing GC,就必需要能完整枚举出全部的GC roots,不然就可能会漏扫描应该存活的对象,致使GC错误回收了这些被漏扫的活对象。

这就像任何递归定义的关系同样,若是只定义了递推项而不定义初始项的话,关系就没法成立——无从开始;而若是初始项定义漏了内容的话,递推出去也会漏内容。

那么分代式GC对GC roots的定义有什么影响呢?
答案是:分代式GC是一种部分收集(partial collection)的作法。在执行部分收集时,从GC堆的非收集部分指向收集部分的引用,也必须做为GC roots的一部分。
具体到分两代的分代式GC来讲,若是第0代叫作young gen,第1代叫作old gen,那么若是有minor GC / young GC只收集young gen里的垃圾,则young gen属于“收集部分”,而old gen属于“非收集部分”,那么从old gen指向young gen的引用就必须做为minor GC / young GC的GC roots的一部分。
继续具体到HotSpot VM里的分两代式GC来讲,除了old gen到young gen的引用以外,有些带有弱引用语义的结构,例如说记录全部当前被加载的类的SystemDictionary、记录字符串常量引用的StringTable等,在young GC时必需要做为strong GC roots,而在收集整堆的full GC时则不会被看做strong GC roots。

换句话说,young GC比full GC的GC roots还要更大一些。若是不能理解这个道理,那整个讨论也就无从谈起了。

顺带放几个传送门:

=================================================

那么分代有什么好处?

对传统的、基本的GC实现来讲,因为它们在GC的整个工做过程当中都要“stop-the-world”,若是能想办法缩短GC一次工做的时间长度就是件重要的事情。若是说收集整个GC堆耗时太长,那不如只收集其中的一部分?
因而就有好几种不一样的划分(partition)GC堆的方式来实现部分收集,而分代式GC就是这其中的一个思路。

这个思路所基于的基本假设你们都很熟悉了:weak generational hypothesis——大部分对象的生命期很短(die young),而没有die young的对象则极可能会存活很长时间(live long)。

这是对过往的不少应用行为分析以后得出的一个假设。基于这个假设,若是让新建立的对象都在young gen里建立,而后频繁收集young gen,则大部分垃圾都能在young GC中被收集掉。因为young gen的大小配置一般只占整个GC堆的较小部分,并且较高的对象死亡率(或者说较低的对象存活率)让它很是适合使用copying算法来收集,这样就不但能下降单次GC的时间长度,还能够提升GC的工做效率。

放几个传送门:

可是!有些比较先进的GC算法是增量式(incremental)的,或者部分并发(mostly-concurrent),或者干脆彻底并发(fully-concurrent)的。
例如鄙司Azul Systems的Zing JVM里的C4 GC,就是一个彻底并发的GC算法。它不存在“GC整个工做流程中都要把应用stop-the-world”的问题——从算法的设计上就不存在。
然而C4却也是一个分两代的分代式GC。为何呢?
C4 GC的前身是Azul System的上一代JVM里的“Pauseless GC”算法,而Pauseless是一个彻底并发可是不分代的GC。

Oracle的HotSpot VM里的G1 GC,在最初设计的时候是不分代的部分并发+增量式GC,然后来在实际投入生产的时候使用的却也是分两代的分代式GC设计。

如今Red Hat正在开发中的Shenandoah GC是一个并发GC,它目前的设计仍是不分代的,但根据过往经验看,它后期渐渐发展为分代式的可能性极其高——若是这个项目能活足够久的话。

对于这些GC来讲,解决stop-the-world时间太长的问题并非选择分代的主要缘由。就Azul的Pauless到C4的发展历程来看,选择实现分代的最大好处是,GC可以应付的应用内存分配速率(allocation rate)能够获得巨大的提高。并发GC根本上要跟应用玩追赶游戏:应用一边在分配,GC一边在收集,若是GC收集的速度能跟得上应用分配的速度,那就一切都很完美;一旦GC开始跟不上了,垃圾就会渐渐堆积起来,最终到可用空间完全耗尽的时候,应用的分配请求就只能暂时等一等了,等GC追遇上来。因此,对于一个并发GC来讲,可以尽快回收出越多空间,就可以应付越高的应用内存分配速率,从而更好地保持GC以完美的并发模式工做。虽然并非全部应用中的对象生命周期都完美吻合weak generational hypothesis的假设,但这个假设在很大范围内仍是适用的,于是也能够帮助并发GC改善性能。

就先写这么多…
相关文章
相关标签/搜索