简述jvm垃圾回收机制,jvm中垃圾回收分为scanvenge gc
00-1010什么是垃圾?什么是GC?怎么找垃圾?垃圾怎么处理?常见的垃圾收集算法mark sweep,copy,Mark Compression,Mark Compact JVM的内存模型是如何实现垃圾收集的?生成模型
00-1010对于程序积累和分配的内存,在使用的时候,这部分内存会变成垃圾,需要释放,否则这部分内存就无法重用,最终造成内存泄漏。
目录
GC是一种自动存储管理机制。当一些被占用的内存不再需要时,它应该被释放。这种存储资源管理称为垃圾收集。对于java,垃圾收集是自动的。
00-1010既然要实现垃圾的自动回收,首先就是要找到垃圾,那么如何找到垃圾呢?其实就是判断这个物体有没有生命。
常见的两种方式判断:
1)引用计数法2)寻根算法名称实现思路优缺点引用计数法给每个对象增加一个引用计数)2。有引用时加1,引用失败时减1。判断效率高1。无法解决相互引用、循环引用的问题. 2。存储空间开销:需要空间来存储计数器。3.时间开销:需要处理计数器的增减。根可达性算法从一系列名为“GC根”的对象开始,并从这些节点向下搜索。搜索的路径叫做参考链。当一个对象连接到GC根而没有任何引用链时,证明该对象是不可用的。解决了循环引用的问题,实现复杂,增加了计算成本。引用计数法(reference count)的循环引用、相互引用:没有外部参考,但它自己的计数器不为0。
由于根可达性算法s引用计数法的问题,所有主流JVM都不使用引用计数法,而是使用根可达性算法.
如上图所示,带有GCRoots的对象表示正在被引用,而其他对象虽然相互有引用,但没有根节点仍然会被删除。
GCRoots对象:什么物体可以变成树根?在jvm中,堆中的内存主要是垃圾回收,而虚拟机栈、本地方法栈和方法区中的对象不会被回收。一般来说,这三个区域中的对象都被选为GCRoots。
在jvm中主要有以下四种,在方法区存在两种:
1)虚拟机堆栈中引用的对象:虚拟机栈帧中的局部变量表所引用的对象. 2)本地方法堆栈中引用的对象:JNI (Native方法)引用的对象. 3)方法区域中的类静态和常量对象:静态变量和常量引用的对象.以下图来展示在JVM内存模型(JMM)的GCRoots:
在根可达性算法中,所有引用都是强引用.下面详细分析jvm中的四个引用。
四种引用::分享了引用JVM的四种方式。
定义名称特征,回收强引用,强引用引用新方法创建的对象。它指的是创建一个对象,并将其赋给一个引用变量;在根搜索算法中,所有引用都指向强引用关系。GC,永远不会回收,这是OOM的主要原因。1.引用消失(例如,方法执行完毕)。2.参考变量被设置为空软参考。如果一个对象有软引用,有足够的内存空间,垃圾收集器就不会回收它;如果内存空间不足,这些对象的内存将被回收。只要垃圾收集器不回收它,程序就可以使用该对象。软引用可以用来实现内存敏感缓存,如网页缓存、图片缓存等。使用软引用可以防止内存泄漏,增强程序的健壮性。在Java中,SoftRefrence用于表示弱引用。当内存不足时(自动触发GC),它将被回收。当内存不足时,触发弱引用的自动回收也用于描述不必要的对象。当JVM执行垃圾收集时,无论是否有足够的内存,与弱引用相关联的对象都将被回收。java中用java.lang.ref.WeakReference类表示无论内存是否充足,只要执行GC,就会被回收。只要执行GC,虚拟引用就会被回收。与以前的软引用和弱引用不同,虚拟引用不影响对象的生命周期。在java中,用java.lang.ref.PhantomReference类表示。诸如
果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。 要注意的是,虚引用必须和引用队列关联使用,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。如同虚设,和没有引用没什么区别任何时候都可能被回收
垃圾如何处理?
我们通过上面学到的根可达性算法可以发现垃圾的所在,那么jvm是如何进行垃圾回收的呢?通过jvm提供的垃圾收集器(GC)。目前有以下种类的垃圾收集器,其中虚线表示垃圾收集器可以进行组合使用:
常见的垃圾收集算法
标记清除(mark sweep):位置不连续 产生碎片 效率偏低(两遍扫描)拷贝算法 (copying):没有碎片,浪费空间标记压缩(mark compact):没有碎片,效率偏低(两遍扫描,指针需要调整)
标记清除(mark sweep)
顾名思义,标记清除算法分为两个阶段标记(mark)和清除(sweep)。标记: Collector从引用根结点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
清除: Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。
对所有能找到根节点引用的内存空间进行标记,清除没有找到根节点的内存空间,其大概实现过程如下:
缺点:
1)STW(stop the word),回收时,应用挂起。2)内存越大,效率越多,需要扫描的时间越长。3)内存碎片化,会导致无法装下新申请的对象,整体内存是足够的,但并非连续的。
拷贝算法 (copying)
拷贝算法将内存空间划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的。当活动区间的内存占满时,接下来GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。
其大概过程如下图所示:
缺点浪费内存,并且存活对象越多的情况下,效率越低。
标记压缩/标记整理(mark compact)
标记过程仍然和标记-清除一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理端边界以外的内存。实现过程大概如下:
缺点效率不高,除了要标记存活对象,还要整理存活对象的引用地址,效率低于复制算法。
总结以上三种算法都是根据根可达性算法实现的。当开始GC时,三种算法都会造成STW(stop the world)。
JVM的内存模型如何实现垃圾回收?分代模型
文章前面介绍了简单很多种垃圾收集器,不同的垃圾收集器有不同的分代模型:1)除Epsilon、ZGC、Shenandoah之外的GC都是使用逻辑分代模型2)G1是逻辑分代,物理不分代3)除1)2)之外不仅逻辑分代,而且物理分代分代模型:
上图中的分代模型有些需要特别关注的点:
1)整个分代模型的组成:新生代 + 老年代 + 永久代(jdk1.7)/元空间(jdk1.8) 永久代、元空间:Class 永久代:必须指定大小限制 元空间:可以设置大小,也可以不设置,无上限(受限于物理内存) 字符串常量池: jdk1.7 - 永久代,jdk1.8 - 堆 MethodArea(方法区)逻辑概念:永久代、元数据2)新生代: Eden + 2个suvivor区 YGC回收之后,大多数的对象会被回收,活着的进入s0 再次YGC,活着的对象eden + s0 -> s1 再次YGC,活着的对象eden + s1 -> s0 年龄足够 -> 老年代 (通常15,对象头Mark Word 的age只有4bit,最大是15 、CMS 6) suvivor区装不下 -> 老年代3)老年代 老年代满了FGC Full GC(STW)GC Tuning尽量减少FGC MinorGC = YGC MajorGC = FGC
到此这篇关于JVM GC 垃圾收集梳理总结的文章就介绍到这了,更多相关JVM GC 垃圾收集 内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。