JVM(二)

什么情况下JVM内存中的一个对象被垃圾回收

正如上图,我们发现新生代有许多实例对象,而其中只有静态变量对应的实例对象有引用,其他都是没有应用的对象,并且有大量的对象,此时新生代可能都要满了,就会触发回收机制

但是我们垃圾回收之前,是要判断那些对象可以被回收,其实在JVM中给出了一种可达性分析算法,判断那些对象可以被回收,那些对象不能被回收,这个算法,就是说每个对象向上追溯,一层层判断,是否有一个GC roots

此时我们就需要知道那些对象可以当做GC roots,比如上图的静态变量,或者说局部变量都可以作为GC roots,即当你的对象被方法的局部变量,类的静态变量给应用了,就不会回收他们

此时我们需要知道对象不同的引用类型,

强引用

一个变量引用一个对象,只需要强引用的类型,那么垃圾回收的时候绝不会去回收这个对象的,如下图代码就是强引用

public class kafka {
  public static RelicaManager replicaManager= new ReplicaManager()
 }

软引用

软引用在正常垃圾回收是不会回收这个对象,只有当发现内存不够用的时候,快要发生内存溢出,就会回收垃圾回收

public class kafka1 {
public static SoftReference<ReplicaManager> replicaManager = 
new SoftReference<ReplicaManager>(new ReplicaManager());
}

弱引用

弱引用就跟没有引用是类似的,如果发生垃圾回收,就会把这个对象回收

public class kafka1 {    
public  static WeakReference<ReplicaManager> replicaManger=
new WeakReference<ReplicaManager>(new ReplicaManager());
}

虚引用

他是最弱的一种引用,他唯一的目的就是在系统回收的时候收到一个系统通知

此时我们还要知道的是假设没有GC Roots对象一定会被回收吗,看下面代码

public class ReplicaManager {
    public static ReplicaManager instance;
@Override
protected void finalize() throws Throwable {
        ReplicaManager.instance = this;
    }
}

如上RelicaManger对象要被垃圾回收的时候,他会检查这个这个对象重写了finalize(),看看是否把自己的实例对象传给了某个GC Roots变量,如果重新让GC Roots变量引用了自己,那么就不会被垃圾回收了.

JVM新生代复制算法的机制

新生代的垃圾回收,按照上面进行处理,内存都是紧凑的排列在内存中,然后进行垃圾回收,就会导致产生许多的内存碎片,此时如果大对象来了,根本存不下,因此新生代采用了一种复制算法的方式进行处理,如下图,

看到上图我们把新生代分为两部分,每部分为500MB,当进行垃圾回收的时候,把垃圾对象移动到上面的内存,存活的对象放到下面的内存中,然后清除上面内存的所有垃圾对象,这样就不会产生内存碎片,

但是,我们发现这样就会导致我们的新生代内存只有一半的内存可以使用,堆内存的使用效率太低了,因此改造成三部分,分别是Eden和Survivor1和Survivor2,

正如上图,survivor1和survivor2分贝占用100M,Eden占用800M,当有对象产生的时候,就会进入Eden和Survivor1,当这个两个区域面的时候,进行垃圾回收,就会把存活的对象放到另外一个survivor2中,这样实际内存使用位900M,同时减少了产生垃圾碎片,

但是同样我们要注意到如果存活的对象超过100M呢,survivor是存不下的,JVM会怎么办,这个后面我们详解解答

什么情况新生代的内存才会进入老年代

第一种,就是新生代快满了,就会进入老年代

第二种,进过了15次垃圾回收的对象,进入老年代,依靠参数设置,默认是15

第三种,大对象直接进入老年代,避免来回复制进入老年代,依赖参数设置默认1M

第四种,survivor的对象大小大于survivor总大小的一半,那么大于等于survivor对象年龄的对象都会进入老年代

如果新生代的存活对象内存大小大于老年代怎么办

这个不得提及老年代的空间担保机制

老年代的回收算法机制

老年代使用的是标记整理算法,进行回收机制,但是这里要注意的是老年代的回收算法比新生代要慢10倍,如下图标记整理算法,把要回收的对象移到到一半,尽量的紧凑靠在一起,然后其他进行一块清除,避免减少过多的内存碎片,如下图

常见的垃圾回收器有那些

serial和serial old 垃圾回收器

分别用来回收新生代和老年代

单线程工作,垃圾回收会停止我们写的系统的其他线程,让系统卡死不动,然后进行垃圾回收,后台系统几乎不可用

ParNew和CMS垃圾回收器

分别用来回收新生代和老年代

他们是多线程并发机制,性能更好

G1

统一收集新生代和老年代

并发收集,低停顿,性能好

Stop The World是意思

我们上面已经知道,在不同分代采用不同的垃圾回收机制,比如新生代采用复制算法,但是我们要考虑一个问题,即使进行垃圾回收时候系统还会产生对象吗,如下图

如果我们在垃圾回收的时候,还有对象不断的产生,就不太好处理了,正如我们打扫房间,但是你家狗总在制造垃圾,那一直打扫都不会清除垃圾的,因此JVM采用下面策略,垃圾回收的时候,系统对外停止使用即STW

STW对系统导致系统不能处理任何请求,正如我的系统正常请求几十ms就返回响应但是正好垃圾回收导致STW,此时十几秒都会返回响应,对用户影响极大,体验度差,我们知道内存设置不合理会导致频繁的GC,因此我们需要尽可能的减少频繁的GC,提高系统的性能

比如不同的垃圾回收器,就会对系统额影响不一样,正新生代的serival垃圾回收器是单线程回收,然后暂停工作线程,因此这种几乎不会被用到,在比如新生代的ParNew,针对多核进行利用,使用多线程,提高了性能,缩短垃圾回收时间,而老年代的CMS,他基于多线程,有一套独特的机制尽可能的减少STW的时间,可以避免长时间卡死我们的系统,

最后得出,合理的优化内存分配和垃圾回收,尽可能减少垃圾回收的频率,境地垃圾回收的时间,减少垃圾回收对系统运行的影响.

本文分享自微信公众号 - 洁癖是一只狗(rookie-dog),作者:洁癖汪

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-03

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JVM(二):画骨

    我们首先来认识一下JVM的运行时数据区域,如果说JVM是一个人,那么运行时数据区域就是这个人的骨架,它支撑着JVM的运行,所以我们先来学习一下运行时数据区域的分...

    山禾说
  • JVM 《二 JVM 中的垃圾回收器 — — CMS&G1》

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

    邹志全
  • JVM第二弹

    当前主流的VM垃圾收集都采用“分代收集“算法,这种算法会根据对象存活周期的不同将内存划分为几块,

    趣学程序-shaofeer
  • JVM(二)Java虚拟机组成详解

    Java虚拟机(Java Virtual Machine)下文简称jvm,上一篇我们对jvm有了大体的认识,进入本文之后我们将具体而详细的介绍jvm的方方面面,...

    Java中文社群-磊哥
  • jvm系列(二):JVM内存结构

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实...

    纯洁的微笑
  • JVM学习(二)

    上一篇文章简单介绍了一下jvm的几个概念。接下来这篇文章将跟大家探讨一下JVM的工作原理。

    一觉睡到小时候
  • JVM学习二

    jps、jstat、jinfo、jhat、jstack、jconsole、jmap、MAT、Btrace、psi_probe监控tomcat,通过gceasy查...

    路行的亚洲
  • JVM 学习笔记二 :JVM内存区域

    方法区主要是在JDK1.8 之前的版本,代表JVM中的一块区域。在JDK1.8以后,这块区域的名字改成了"Metaspace",可以认为是 元数据空间的意思。当...

    一枝花算不算浪漫
  • 深入理解JVM(二)——揭开HotSpot对象创建的奥秘

    对象的创建过程 当虚拟机遇到一条含有new的指令时,会进行一系列对象创建的操作: 检查常量池中是否有即将要创建的这个对象所属的类的符号引用; 若常量池中没...

    大闲人柴毛毛
  • 十个问题弄清JVM&GC(二)

    每个java开发同学不管是日常工作中还是面试里,都会遇到JDK、JVM和GC的问题。本文会从以下10个问题为切入点,带着大家一起全面了解一下JVM的方方面面。

    宜信技术学院
  • JVM | OOP-Klass 二分模型

    oopsHierarchy: 描述了对象的表示层次,描述了klass的表示层次,并为OOPS指针oopDesc* 定义了别名

    微笑的小小刀
  • jvm详解——第二篇Jvm垃圾回收机制详解

    堆是在 JVM 启动时创建的,主要用来维护运行时数据,如运行过程中创建的对象和数组都是基于这块内存空间。Java 堆是非常重要的元素,如果我们动态创建的对象没有...

    胡齐
  • 用Java实现JVM第二章《搜索class文件》

    案例简述 本章节主要了解Java虚拟机从哪里寻找class文件并且读取class内字节码

    小傅哥
  • 用Java实现JVM第二章《搜索class文件》

    Notepad++ 打开HelloWorld.class,在'插件'工具中选HEX-Editor设置为View in Hex 默认为8-bit

    小傅哥
  • JVM 学习笔记(二)

    如果还不明白什么是栈帧,可以参考:https://www.jianshu.com/p/b666213cdd8a

    会说话的丶猫
  • JVM调优(二)经验参数设置

        JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下...

    小勇DW3
  • JVM系列二(垃圾收集算法).

    这种算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

    JMCui
  • JVM笔记二双亲委派机制

    JVM类加载器是什么机制?为什么使用这种机制(这种机制的好处是什么)?说下类加载流程?用代码验证类加载机制。为什么要破坏类的这种加载机制?

    凯哥Java
  • Java虚拟机(二):JVM内存模型

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实...

    朝雨忆轻尘

扫码关注云+社区

领取腾讯云代金券