专栏首页洁癖是一只狗如何优化垃圾回收机制

如何优化垃圾回收机制

我们知道之所以java比较容易上手,很大的原因是由于我们不需要关注对象的回收和释放,可以减少不少的工作量,但是完全交由虚拟机回收,也会带来回收性的不确定性。

面对不同的业务场景,垃圾回收的调优策略也是不一样的,例如在内存要求苛刻的情况下,需要提高回收策略,在CPU使用率高的情况下,需要降低高并发量时垃圾回收的频率。所以垃圾回收调优是一项必备技能

垃圾回收机制

首先,我们要弄明白三件事

  1. 回收发生在哪里
  2. 对象什么时候回收
  3. 如何回收这些对象

回收发生在哪里

JVM内存模型中,程序计数器,虚拟机栈和本地方法栈这个三个区域是线程私有的,随着线程的创建而创建,销毁而销毁,栈中的帧栈随着方法的进入和退出进行入栈和出栈,每个帧栈中分配多少内存基本是类机构确定下来的时候就已经确定了,因此这三个区域内存的分配和回收是确定的

但是堆和方法区就是垃圾回收的重点,堆中回收的主要是对象的回收,方法区的回收主要是废弃常量和无用的类的回收

对象什么时候可以回收

JVM如何判断一个对象是否可以被回收,一般一个对象不再被引用,就代表这对象可以被回收,目前有两种方式判断对象时候被回收

引用计数器,这种算法是根据对象的引用计数器来判断对象是否被应用,每当对象被引用,引用计数器就会加1,当对象引用时效,引用计数器就减1,当引用计数器值为0时候,就说明该对象不在被引用,可以被回收,虽然此算法简单,但是无法解决循环引用的问题

可达性分析算法,GC Roots是该算法的基础,GC Roots是所有对象的根对象,在JVM加载时候,会创建一些普通对象引用正常对象,这些对象作为正常对象的起始点,在垃圾回收时候,从这个GC Roots开始向下搜索,当一个对象到GC Roots没有任何引用链相连时,就证明这个对象不可应,目前HotSpot虚拟机就是采用这个算法

在JDK1.2之后,java对引用的概念进行了扩展分为了四种

  1. 强引用,被强引用关联的对象永远不会被回收
  2. 软引用,软引用在系统将要发生内存溢出时候,进行回收
  3. 弱引用,只被弱引用关联的对象,只要发生垃圾回收事件,就会被回收
  4. 虚引用,他的唯一作用就是在被回收器回收的时候发出一个系统通知

如何回收对象

了解完回收的条件,那么垃圾回收线程又是如何回收这些对象的,垃圾回收遵循下面两点特性

自动型,Java提供一个系统级的线程来跟踪每一块分配出去的内存,当JVM处于空闲循环时,垃圾收集器线程会自动检查每一块分配出去的内存空间,然后自动回收每一个空闲的内存块

不可预期性,一旦一个对象没有被引用了,该对象是否立刻被回收呢,答案是不可预期的,因为有可能程序结束后,这个对象扔在内存中。

垃圾收集线程在JVM中是自动执行的,java程序无法强制执行,我们唯一能做的就是调用system.gc方法来建议执行垃圾收集器,但是是否立刻执行,仍然是不可预期的

GC算法

回收算法

优点

缺点

标记-清除

不需要移动对象,简单高效

效率低,GC产生内存碎片

复制

简单高效,不会产生内存碎片

内存使用率低,产生频繁的复制问题

标记-整理

结合上面两种算法优点

仍需移动局部对象

分代收集算法

分区会后

对于长时间存活对象的场景的回收效果不明显,甚至起到分作用

垃圾收集器就是内存回收的具体实现,下面就是具体的垃圾收集器

回收类型

回收算法

特点

Serial New/Serial Old

复制算法/标记-整理

单线程复制回收,简单高效,但会暂停程序导致停顿

ParNew New/ParNew Old

复制算法/标记整理

多线程复制回收,降低停顿时间,但容易增加上下切换

Parallel Scavenge

复制算法

并行回收期,追求高吞吐量,高效利用CPU

CMS

标记-清除

老年代回收期,高并发,低停顿,追求最短GC回收停顿时间,CPU占用比较高,响应时间快,停顿耗时间短

G1

标记-整理+复制算法

高并发,低停顿,可预测停顿时间

GC性能衡量指标

吞吐量:这里吞吐量是指应用程序所花费的时间和系统总运行时间比值,系统总运行时间=应用程序耗时+GC耗时,比如系统运行了100分钟,GC耗时1分钟,吞吐量就是99%,一般吞吐量一般不低于95%

停顿时间:指垃圾收集器正在运行时,应用程序暂停时间,对于串行回收期而言,停顿时间较长,并行回收期,停顿时间较短。但是效率很可能不如串行垃圾收集器,系统的吞吐量也可能降低

垃圾回收效率:通常垃圾回收的频率越低越好,增大对内存空间可以有效降低垃圾回收发生的频率,但是同时意味着堆积的回收对象越多,最终会增加回收时的停顿时间,所以我们只要适当的增大堆内存空间,保证正常的垃圾回收频率即可

GC调用策略

降低Minor GC频率

通常情况下,由于新生代空间较小,Eden区很快填满,就会导致频繁Minor GC,因此增加新生代空间来降低Minor GC的频率

此时我们就有了疑问,扩容Eden区虽然可以降低Minor GC,但是是不是增加了单次Minor GC.

我们知道,单次Minor GC时间是有两部分组成T1(扫描新生代)T2(复制存活对象),假设一个对象的存活对象为500ms,Minor GC的时间间隔是300ms,那么正常情况下,Minor GC时间T1+T2

而当我们增大新生代空间,Minor GC时间间隔会扩大到600ms,此时一个存活的随想就会在Eden会被回收,此时就不存在复制存在对象,所以在发生Minor gc时间就是两次扫描新生代即2T1

可见,扩容后,Minor GC即增加了T1但省去了T2的时间,通常复制对象的成本要远高于扫描成本。

如果在堆内存中存在较多的长期存活的对象,我们扩大新生代的空间,反而会增加Minor GC的时间,如果堆中的短期对象很多,那么扩容新生代空间,单次Minor GC时间不会明显增加,因此单次Minor GC时间更多取决于GC后存活的对象数量,并非Eden区的大小

降低Full GC频率

由于堆内存空间不足或老年代对象太多,会频繁的发生Full GC,因此会带来上下文切换,增加系统的性能开销.我们可以使用下面方式降低Full GC的频率

  1. 减少创建大的对象 平常中我们可能会从数据库中获取一个大的对象,例如插入的对象有60个字段,这种对象如果超过年轻代最大对象的阀值,会被直接分配在老年代,即使创建年轻代,由于年轻代的内存空间有限,通过Minor GC也会进入老年代,这种大对象很容易产生较多的Full GC
  2. 增加堆内存空间 在堆内存不足的时候,增大堆内存空间,且设置初始化堆内存为最大堆内存,也可以降低Full GC频率
  3. 选择合适的GC回收器 如果我们需要操作响应时间必须500ms内需求,就可以选择速度较快的回收期,如CMS和G1就是不错的选择,而当我们需求对吞吐量有要求时候,就可以选择Paraller Scavenge回收期提高系统的吞吐量

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

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

原始发表时间:2021-01-11

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 知道如何优化垃圾回收机制吗?

    在 Java 开发中,开发人员是无需过度关注对象的回收与释放的,JVM 的垃圾回收机制可以减轻不少工作量。但完全交由 JVM 回收对象,也会增加回收性能的不确定...

    田维常
  • 垃圾回收机制

      我们定义变量会申请内存空间来存放变量的值,而内存的容量是有限的,当一个变量值没有用了(称为垃圾),就应该将其占用的内存给回收掉。变量名是访问到变量的唯一方式...

    py3study
  • [PHP]垃圾回收机制

    2. 在zval结构体中定义了ref_count和is_ref , ref_count是引用计数 ,标识此zval被多少个变量引用 , 为0时会被销毁 is_r...

    陶士涵
  • JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)

      按照套路是要先装装X,谈谈JVM垃圾回收的前世今生的。说起垃圾回收(GC),大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史比Java久远...

    哲洛不闹
  • Java垃圾回收机制

    垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部...

    java达人
  • PHP垃圾回收机制

    1、每一个变量定义时都保存在一个叫zval的容器里面,这里面包含了数量的类型和和值,还包含了一个refcount(理解为存在几个变量个数)和is_ref(理解为...

    思梦php
  • Java 垃圾回收机制

    自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未...

    我就是马云飞
  • Java垃圾回收机制

    在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾回收意味着程序不再需要的对象是"无用...

    用户2909867
  • PHP垃圾回收机制

    PHP垃圾回收机制 1、每一个变量定义时都保存在一个叫zval的容器里面,这里面包含了数量的类型和和值,还包含了一个refcount(理解为存在几个变量个数)和...

    思梦php
  • PHP垃圾回收机制

    1、每一个变量定义时都保存在一个叫zval的容器里面,这里面包含了数量的类型和和值,还包含了一个refcount(理解为存在几个变量个数)和is_ref(理解为...

    思梦php
  • JS 垃圾回收机制

    1、自动垃圾回收机制就是找出那些不再继续使用的值,然后释放其占用的内存空间。垃圾回收器每隔固定的时间段就执行一次释放操作。

    grain先森
  • JVM 垃圾回收机制

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

    烟草的香味
  • JAVA垃圾回收机制

    PS:不管是调优也好,先是配合对应的新老对应的垃圾收集器,如果有必要才修改垃圾收集器的参数的,垃圾回收器如何标记垃圾,如何进行垃圾收集的,收集器有哪些?它们是如...

    IT架构圈
  • 016. 垃圾回收机制

    山海散人
  • Python垃圾回收机制

    管理内存的基本问题是知道什么时候保留它包含的数据,什么时候丢弃它,以便可以重用内存。这听起来很容易,但实际上是一个难题,它本身就是整个研究领域。在理想的世界中,...

    宇宙之一粟
  • JVM垃圾回收机制

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

    Liusy
  • day09(垃圾回收机制)

    py3study
  • docker垃圾回收机制

    对于Docker来说,存在镜像/容器/存储卷和网络(iptables规则)这些对象.因此docker也会产生出这些对应的对象,这些对象会占据磁盘空间,当这些对象...

    张琳兮
  • docker垃圾回收机制

    对于Docker来说,存在镜像/容器/存储卷和网络(iptables规则)这些对象.因此docker也会产生出这些对应的对象,这些对象会占据磁盘空间,当这些对象...

    张琳兮

扫码关注云+社区

领取腾讯云代金券