专栏首页EffectiveCodingJVM 《一 JVM 中的垃圾回收》

JVM 《一 JVM 中的垃圾回收》

上一篇我们介绍了JVM,还有JVM中的内存结构。

当我们了解其中的内存之后,我们可能会有一点想法,我们的对象、相关类信息是存放在Java堆、方法区之中的。那我们的程序正在不断的new 对象、不断的loading Class。那么我们的JVM为什么没炸了(OOM),即使数量不会多到炸,但是我们不用的那些对象难道一直要仍在内存中?

cpp这样的语言,程序员是对自己的对象负责的,用完之后得了结了它。那Java呢?类似于以上的问题,是依靠JVM的垃圾回收机制去处理那些废弃的对象还有类信息的。

垃圾:废弃的对象、类信息、常量

回收:如何标记垃圾、如何清扫垃圾

垃圾的定义是比较巧妙的,JVM需要完完全全的确定我们不再使用了,才将其定义为垃圾。

《深入理解Java 虚拟机》一书中对什么是垃圾有一个有趣的标题— — 对象已死?

首先说 废弃的对象:

      当一个对象,对我们来说是不可见、并且不可达的。那么如何判断 有这么两种方式或方法

1> 引用计数法:判断程序是否对这个对象还持有引用(这个对象是否还有使用的可能)

这个方法的优缺点显而易见,效率高,但是很有可能出现循环引用。

2>可达性分析:在说可达性之前,先说一个概念叫做GCRoot(既JVM 垃圾回收中判断对象是否可达的起点,是否仍被使用的起始节点),GCRoot常常有这么几个点:栈中所引用的对象(既被方法中直接使用的对象)、方法区中静态元素所引用的对象。

当我们有了GCRoot之后,我们便可以从它们出发去探索我们的对象了,那些不可达的也就可以被判断为应该不会被使用。也就一定程度上可以被标记待回收。

为了好理解,还是画个图吧

image.png

然后知道如何辨别和标记处垃圾之后,剩下的便是清理工作了。

JVM中的垃圾清扫或者收集算法有这么几种:标记-清除、标记-整理、复制、分代回收

标记-清除:

见明知义,先标记再清除(容易实现,但是效率较低、容易产生大量的内存碎片),放个图更好理解吧

image.png

针对内存碎片这个事儿,JVM也算是做出了不少策略。比如下面的,标记整理、复制

标记整理:

清扫掉废弃对象、并且整理,虽然没有内存碎片了,但是需要额外的整理工作,不仅需要标记存活的对象,还需要整理所有存活对象的引用地址。

放个图吧~

image.png

复制:其实是回收时将内存分为两部分,然后将存活的对象收集起来,清除掉待会收区域的垃圾就好啦。效率比标记整理要高,但是浪费了一部分空间。

image.png

JVM是可以这么玩复制算法的,新生代划分为三块区域(Eden区、2个Survival区,这其实就是种简单的面相程序员的一种抽象而已,具体低层实现比这个要复杂的多),其中默认Eden:Survival ==8:1,这个是要根据具体的对象的存活率来定的,为啥?别急,慢慢来。

首先新产生的对象是放在Eden中的,然后GC的时候是将存活对象取出来放到一个Survival(存活区)中,然后回收完成,继续向Eden中扔对象,下一次回收的时候是回收Eden及存放存活对象的那个Survival中,然后把这次的GC幸存者放在空的Survival中,然后回收完成,继续向Eden中扔对象,下一次回收的时候是回收Eden及存放存活对象的那个Survival中,然后把这次的GC幸存者放在空的Survival中(依次循环,我就不复制文字了,其中经历好多次的老对象到达年龄后是被请到老年区的。根据存活率控制空间比值是很重要哒,省的动不动向老年代抛对象)

image.png

然后是分代收集:就是按照对象年龄(经历的回收次数)作为主要标准,对Java Heap进行分区处理,之前作为简单例子说复制的时候提到过。

然后生命周期短的对象、生命周期长的对象,所采取的应该是不一样的,因为对象的存活率差太多。比如标记整理适合老年代,标记清除新生代也可以使用。这些在Java Heap 对象回收的时候其实是配合使用的。具体JVM使用哪种算法,其实是按照垃圾回收器来定的,感觉分代回收很高级的样子,其实在G1中已经弱化分代了。感觉标记-清除那么些毛病,为啥CMS使用它。每个具体的回收算法都有自己的优点和缺点,对这些算法进行合理的优化,相互配合在对象存活率不同的区域使用才能发挥更好的效果。具体的算法或者垃圾回收器的选择,要根据现实世界问题情形及相关物理硬件条件。

然后是对于废弃常量还有类的回收(方法区的回收)

就一点何为废弃的类:

1>该类所有的实例都已经被回收

2>加载该方法的ClassLoader已经被回收

3>该类对应的Class对象已无引用,并且无法通过反射访问。

但满足以上条件时,是允许进行回收的。

并且方法区也是会有溢出风险的,而且也会有废弃产生。所以也具有回收的意义,尤其是在大量反射使用的场景。

然后提几个中间没说到的东西:

1> Stop the world,在对象进行可达性分析的时候,会出现一次骤停(停止在使用对象的线程),然后标记线程启动,对对象进行标记。(并不是一下子让所有线程停止、而是让线程在安全点自行暂停)

2> finalize( ) ,这是每本书都不推荐使用的方法。它是在回收过程中自动执行的,并且仅执行一次。不同于cpp中的析构函数,这个不是来销毁对象的,据说是用来做一些对象销毁前必要的清理工作的。存在内存泄漏的风险。而且这个会让本来在回收流程中的对象复活(仅仅需要在方法中把对象的引用传给一个GCRoot可达的地方就好)。

3>Java 引用相关(传送门~)

4> 大对象直接进入老年代

下一篇 或者 后面几篇 说具体的垃圾回收器,以G1为主,CMS也会说一说。其他那些会大体提一提(较为简单,篇幅不大),然后是关于GC日志分析的。

具体怎么调优和选择,还有我们编码相关的注意事项会在调优那一篇章进行描述~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JVM --- 垃圾回收

    那么哪种回收算法最好呢?没有最好,只有最合适。复制算法省时间,但是耗空间,标记整理算法不耗费额外的空间,但是费时间。新生区因为对象存活率底,所以适合用复制算法,...

    贪挽懒月
  • JVM的垃圾回收

    垃圾回收机制是java的一个特性,相较于c/c++程序员需要自己分配内存,在使用结束后自己回收内存而言,Java实在对程序员太友好了(所以头发较多点)。Java...

    用户3467126
  • JVM之垃圾回收

    对象是否存活: ①.引用计数算法: 描述:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收. 优势:简单高效...

    用户1215919
  • JVM垃圾回收(下)

    接着上一篇,介绍完了 JVM 中识别需要回收的垃圾对象之后,这一篇我们来说说 JVM 是如何进行垃圾回收。

    健程之道
  • JVM垃圾回收(上)

    Java 中的垃圾回收,常常是由 JVM 帮我们做好的。虽然这节省了大家很多的学习的成本,提高了项目的执行效率,但是当项目变得越来越复杂,用户量越来越大时,还是...

    健程之道
  • JVM|04垃圾回收

    程序的运行必然需要申请内存资源,无效的对象资源如果不及时处理就会一直占有内存资源,最终将导致内存溢出,所以对内存资源的管理是非常重要了。

    微笑的小小刀
  • JVM垃圾回收二:分代垃圾回收

    分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。 在Java程序运行的...

    哲洛不闹
  • jvm垃圾回收以及垃圾回收器

    ? ? ? ? ? ? ? 垃圾回收器 ? ? ? ? ? ?

    lyb-geek
  • JVM 《二 JVM 中的垃圾回收器 — — CMS&G1》

    这是最常见的两个垃圾回收器,也是现阶段JVM中使用的最多的。 先说CMS,Concurrent Mark Sweep,,名字全称是Concurrent Low...

    邹志全
  • JVM 《三 JVM 中的垃圾回收器 — — 其他》

    除去上一篇说的CMS,剩下的都是这几类了,然后根据Old or New 自行分配就好了

    邹志全
  • JVM之垃圾回收-垃圾收集器

    如果说前面介绍的收集算法(JVM之垃圾回收-垃圾收集算法)是内存回收的抽象策略,那么垃圾收集器就是内存回收的具体实现。

    谙忆
  • JVM垃圾回收算法

    java404
  • Hotspot JVM垃圾回收器

      前两篇《JVM入门——运行时数据区》《JVM常见垃圾回收算法》所提到的实际上JVM规范以及常用的垃圾回收算法,具体的JVM实现实际上不止一种,有JRocki...

    用户1148394
  • 探究JVM——垃圾回收

    垃圾回收主要考虑三件事情:哪些内存需要回收?什么时候回收?如何回收? 一、哪些内存需要回收? 堆内存:对于JVM 来说,垃圾回收主要是针对堆内存中的对象实例。 ...

    欠扁的小篮子
  • JVM-5. 垃圾回收器

    悠扬前奏
  • JVM 垃圾回收机制

    首先JVM的内存结构包括五大区域: 程序计数器、虚拟机栈、本地方法栈、方法区、堆区。其中程序计数器、虚拟机栈和本地方法栈3个区域随线程启动与销毁, 因此这几个区...

    烟草的香味
  • JVM 垃圾回收算法

    在标记阶段首先通过根节点(GC Roots),标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。

    一个会写诗的程序员
  • JVM垃圾回收机制

    JVM垃圾回收机制是java程序员必须要了解的知识,对于程序调优具有很大的帮助(同时也是大厂面试必问题)。

    Liusy
  • jvm垃圾回收算法

    云123

扫码关注云+社区

领取腾讯云代金券