热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

GCroots

1.虚拟机栈(本地变量表)引用的对象2.方法区静态属性引用的对象3.方法区常量引用的对象4.本地方法栈JNI(一般指naive方法)中引用的对象 常说的GC(GarbageColl

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


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

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

一个对象可以属于多个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的示例图:

 

作者: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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 


 

参考:

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

 


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

题主对“GC roots”的概念的理解完全错误
如果题主是把“GC roots”(根引用集合)实质上理解成了“live set”(存活的对象的集合)的概念的话,这就好理解了。否则很难理解题主想说的是什么意思。

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

题主说:
我的理解是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还要更大一些。如果不能理解这个道理,那整个讨论也就无从谈起了。

顺带放几个传送门:
  • Major GC和Full GC的区别是什么?触发条件呢?- RednaxelaFX 的回答 - 知乎
  • 主流的垃圾回收机制都有哪些? - RednaxelaFX 的回答 - 知乎
  • 关于CMS、G1垃圾回收器的重新标记、最终标记疑惑? - RednaxelaFX 的回答 - 知乎
  • 火车算法在目前在哪些JVM中有用到,G1吗? - RednaxelaFX 的回答 - 知乎

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

那么分代有什么好处?

对传统的、基本的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的工作效率。

放几个传送门:
  • JVM GC遍历一次新生代所有对象是否可达需要多久?- RednaxelaFX 的回答 - 知乎
  • 有关 Copying GC 的疑问?- RednaxelaFX 的回答 - 知乎

但是!有些比较先进的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改善性能。

就先写这么多…

推荐阅读
  • 本文深入探讨了CGLIB BeanCopier在Bean对象复制中的应用及其优化技巧。相较于Spring的BeanUtils和Apache的BeanUtils,CGLIB BeanCopier在性能上具有显著优势。通过详细分析其内部机制和使用场景,本文提供了多种优化方法,帮助开发者在实际项目中更高效地利用这一工具。此外,文章还讨论了CGLIB BeanCopier在复杂对象结构和大规模数据处理中的表现,为读者提供了实用的参考和建议。 ... [详细]
  • 如何高效启动大数据应用之旅?
    在前一篇文章中,我探讨了大数据的定义及其与数据挖掘的区别。本文将重点介绍如何高效启动大数据应用项目,涵盖关键步骤和最佳实践,帮助读者快速踏上大数据之旅。 ... [详细]
  • 在CentOS 7上部署WebRTC网关Janus
    在CentOS 7上部署WebRTC网关Janus ... [详细]
  • 分布式开源任务调度框架 TBSchedule 深度解析与应用实践
    本文深入解析了分布式开源任务调度框架 TBSchedule 的核心原理与应用场景,并通过实际案例详细介绍了其部署与使用方法。首先,从源码下载开始,详细阐述了 TBSchedule 的安装步骤和配置要点。接着,探讨了该框架在大规模分布式环境中的性能优化策略,以及如何通过灵活的任务调度机制提升系统效率。最后,结合具体实例,展示了 TBSchedule 在实际项目中的应用效果,为开发者提供了宝贵的实践经验。 ... [详细]
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • Android目录遍历工具 | AppCrawler自动化测试进阶(第二部分):个性化配置详解
    终于迎来了“足不出户也能为社会贡献力量”的时刻,但有追求的测试工程师绝不会让自己的生活变得乏味。与其在家消磨时光,不如利用这段时间深入研究和提升自己的技术能力,特别是对AppCrawler自动化测试工具的个性化配置进行详细探索。这不仅能够提高测试效率,还能为项目带来更多的价值。 ... [详细]
  • 本文详细介绍了 jQuery 的入门知识与实战应用,首先讲解了如何引入 jQuery 库及入口函数的使用方法,为初学者提供了清晰的操作指南。此外,还深入探讨了 jQuery 在实际项目中的多种应用场景,包括 DOM 操作、事件处理和 AJAX 请求等,帮助读者全面掌握 jQuery 的核心功能与技巧。 ... [详细]
  • CentOS 7环境下Jenkins的安装与前后端应用部署详解
    CentOS 7环境下Jenkins的安装与前后端应用部署详解 ... [详细]
  • 如何在IntelliJ IDEA中生成Maven项目的所有Jar包依赖关系图
    本文详细介绍了如何在IntelliJ IDEA中生成Maven项目的完整Jar包依赖关系图。通过具体步骤和示例,帮助开发者清晰地理解并掌握这一重要功能,适合希望深入了解Maven依赖管理的读者学习参考。 ... [详细]
  • Deepin 20 系统源更换指南及基础设置教程
    配置目标:创建一个适合基本娱乐、办公和直播的环境。安装方法:手动分区。系统要求:EFI分区需大于500MB,根分区建议至少20GB,以确保系统稳定运行和足够的存储空间。此外,建议分配适量的交换分区,以提升系统性能和响应速度。 ... [详细]
  • Java 模式原型在游戏服务器架构中的应用与优化 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • 在Spring框架中,基于Schema的异常通知与环绕通知的实现方法具有重要的实践价值。首先,对于异常通知,需要创建一个实现ThrowsAdvice接口的通知类。尽管ThrowsAdvice接口本身不包含任何方法,但开发者需自定义方法来处理异常情况。此外,环绕通知则通过实现MethodInterceptor接口来实现,允许在方法调用前后执行特定逻辑,从而增强功能或进行必要的控制。这两种通知机制的结合使用,能够有效提升应用程序的健壮性和灵活性。 ... [详细]
  • 本文深入探讨了NDK与JNI技术在实际项目中的应用及其学习路径。通过分析工程目录结构和关键代码示例,详细介绍了如何在Android开发中高效利用NDK和JNI,实现高性能计算和跨平台功能。同时,文章还提供了从基础概念到高级实践的系统学习指南,帮助开发者快速掌握这些关键技术。 ... [详细]
author-avatar
梦亦碎i
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有