JVM垃圾回收篇

点赞再看,养成习惯,微信搜索「 小大白日志」关注这个搬砖人。

文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。

基础概念

  • GC=jvm垃圾回收,垃圾回收机制是由垃圾回收器Garbage Collection来实现的。进行GC的线程是后台的守护进程(后台运行、执行特定任务),它是一个低优先级进程;当可用内存低到一定程度时,自动运行(自启),从而实现对内存的回收,故垃圾回收的时间不确定;
  • 浮动垃圾:jvm回收垃圾的同时,垃圾还在尝试产生,这些就是”浮动垃圾”,即”floating Garbage”,只能等到下次GC的时候清理
  • 并行收集:垃圾回收器工作时,用户线程停止,只有多个垃圾回收线程在并行地收集垃圾
  • 并发收集:垃圾回收时,用户线程不停止,而是直接和垃圾回收线程并发地工作

如何判断对象是否是垃圾?

两种方法:引用计数法、可达性分析法(常用这种)

  • 引用计数法

每个对象都有一个引用计数器,当有地方引用该对象时,计数器+1;删除引用或引用失效时,计数器-1;当计数器=0时,说明对象没有被引用则可以被JVM回收;

优点:实现简单,判断效率高

缺点:不能解决循环引用问题

  • 可达性分析

jvm中有一部分对象可被称为【GC roots对象】,如:被栈中引用的对象、被常量引用的对象、被静态变量引用的对象,从【GC roots对象】开始向下遍历,遍历过程中与【GC roots对象】形成通路的对象则为’可达’对象=存活的对象=尚存在引用的对象,否则为’不可达’对象=死亡的对象=不存在引用的对象,当某个对象不可达时,说明对象没有被引用则可以被JVM回收

当对象被判定为垃圾对象后有何方法回收?

5种gc算法

  • 引用计数法

每个对象都会有一个引用计数器,对象增加一个引用则计数器+1,减少一个引用则计数器-1,垃圾回收时,只回收计数器为0的对象。
缺点:无法处理循环引用的情况

  • 标记清除算法

分为标记阶段和清除阶段,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象,而未被标记的对象就是未被引用的垃圾对象;然后,在清除阶段,清除所有未被标记的对象。
缺点:标记清除后会产生大量不连续的内存碎片,内存碎片太多可能会导致以后程序运行过程中需要分配较大内存对象时,无法找到足够的连续的内存

  • 标记整理算法

标记过程仍然与”标记清除”算法一样,但是后续步骤不是直接对未标记的对象进行清除,而是先让所有标记的对象都向一端移动,然后直接清除掉该端边界以外的内存,解决了没有足够大的连续内存的问题

  • 复制算法

将可用的内存按照容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将活着的对象复制到另外一块上面,然后再把使用过的那一半内存空间一次清理掉。每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况。
缺点:可用内存缩小为原来的一半。

  • 分代收集算法

java堆分成新生代和老年代,分带收集算法=新生代采用赋值算法+老年代采用标记整理算法。在新生代中,每次垃圾回收时都发现大批对象的死去,只有少量存活,故采用复制算法可以只付出少量存活对象的复制成本就可以完成收集;而老年代中因为对象存活率高,没有足够的空间让出来作垃圾回收,故使用”标记整理”算法来进行回收。

谁来回收?

用7种垃圾收集器来回收,可以对应地记忆:

串行收集器 并行收集器 吞吐量收集器 串行老年代收集器 CMS收集器 吞吐量老年代收集器 G1收集器 如上,串行收集器

吞吐量收集器

并行收集器

再加上一个G1收集器,共7种收集器,这7种收集器可分别作用于新生代和老年代:

JVM垃圾回收篇

图中上下半部为新生代、老年代对应可用的收集器,连线代表可以结合使用

  • 串行收集器(Serial收集器)
  • 作用于新生代,故使用复制算法;
  • 仅仅使用一个线程完成垃圾收集工作;
  • 在垃圾收集时必须暂停其他所有的工作线程(stop-the-world),直到垃圾收集结束;
  • 专心做垃圾收集故效率比较高,使用【-XX:+UseSerialGC】打开

JVM垃圾回收篇
  • 并行收集器(ParNew收集器)
  • 作用于新生代,故使用复制算法;
  • 并行收集器其实是串行收集器的多线程版本,与Serial收集器唯一不同的地方就是在垃圾收集过程中使用多个线程并行收集,其他全部和串行收集器相同
  • 它默认开启的收集线程数与CPU的数量相同
  • 使用【-XX:UseParNewGC】打开;

除了Serial收集器,就只有它能和CMS收集器混合使用

JVM垃圾回收篇
  • 吞吐量收集器(ParallelScavenge 收集器)
  • 作用于新生代,故使用复制算法;
  • 吞吐量收集器的目的是追求高吞吐量,吞吐量=运行用户代码时间/(运行用户代码时间+运行垃圾收集时间);
  • 使用【-XX:+UseParallelGC】打开;使用【-XX:MaxGCPauseMillis】指定垃圾收集最大停顿时间,但并非越小越好;
  • 使用多个GC线程来完成垃圾收集
  • 会引起stop-the-world(垃圾收集停顿时间:垃圾收集的时候,所有java线程被挂起,除了垃圾收集器的线程,此时navtive相关代码可执行但不能与JVM交互,故stop-the-world是大家的敌人)
  • 最大的特点是’GC自适应策略”:打开GC自适应策略【-XX:+UseAdaptiveSizePolicy】,则不用再手动设置’年轻代:老年代’的大小、’Eden区:survivor区’的大小、对象晋升老年代的年龄,系统会根据实时性能去动态设置这些参数以便达到最高的吞吐量、最优的停顿时间
    JVM垃圾回收篇
  • 串行老年代收集器(Serial Old收集器)
  • 因为作用于老年代,所有采用’标记整理’算法
  • 和串行收集器一样,只是它作用于老年代,是串行收集器的老年代版本

JVM垃圾回收篇
  • CMS收集器
  • 作用于老年代,故使用’标记整理’算法;
  • 以获取最短的垃圾收集停顿时间为目标,重视响应速度和用户体验的应用;
  • CMS收集器的内存回收过程是与用户线程一共并发执行的;
  • 使用【-XX:+UseConcMarkSweepGC】打开;
  • 步骤:初始标记->并发标记->重新标记->并发清除,初始阶段=标记由【GC roots】直接到达的对象,并发标记=标记由【GC roots】间接到达的对象,重新标记=修正在’并发标记’期间由于用户程序运行而导致标记变动的标记,并发清除=清除已标记的对象

JVM垃圾回收篇
  • 吞吐量老年代收集器(Parallel Old收集器)
  • 因为作用于老年代,所有采用’标记整理’算法
  • 和吞吐量收集器一样,只是它作用于老年代,是吞吐量收集器的老年代版本
  • 使用【-XX:+UseConcMarkSweepGC】打开

JVM垃圾回收篇
  • G1收集器
  • 可作用于年轻代/老年代,jdk1.9之后的默认垃圾收集器
  • 使用【-XX:+UseG1GC】打开
  • G1收集器的内存回收过程是与用户线程一起并发执行的;
  • G1收集器不会产生内存碎片,会把内存碎片收集后形成大的内存块
  • G1收集器最大的特点是把堆的内存分成一块块大小相同的区域(region),保留年轻代、老年代的概念,但年轻代、老年代也是被清晰地分为一个个区域
  • G1追求最小的gc停顿时间,并且可用参数指定gc停顿时间,也就是建立了可以预测的gc停顿时间模型,原理:因为G1收集器把堆分成了一块块大小相同的区域,每个区域可以回收的空间大小不同,G1会在后台把每个区域的回收价值(回收价值=可回收的空间大小+回收时间成本)由大到小维护成一张优先级列表,回收是先回收价值大的区域;每个区域的大小可以通过【-XX:G1HeapRegionSize】参数指定,大小区间最小1M、最大32M,一定要是2的幂次方,默认把堆内存按照2048份均分,每个区域被标记了E、S、O和H,这些区域在逻辑上被映射为Eden、Survivor、老年代Old和Humongous去(用来存放大对象)
  • 步骤:初始标记->并发标记->重新标记->筛选回收,初始阶段=标记由【GC roots】直接到达的对象,并发标记=标记由【GC roots】间接到达的对象,重新标记=修正在’并发标记’期间由于用户程序运行而导致标记变动的标记,筛选回收=对各个region计算回收价值(回收价值=可回收的空间大小+回收时间成本),并按照用户设置的停顿时间来制定回收计划

JVM垃圾回收篇

JVM垃圾回收篇

默认的垃圾回收器

jdk1.7和jdk1.8: 年轻代默认’吞吐量垃圾收集器’(即Parallel Scavenge), 老年代默认’吞吐量老年代收集器’(即Parallel Old)

jdk1.9:默认G1垃圾收集器

OK,如果文章哪里有错误或不足,欢迎各位留言。

创作不易,各位的「 三连」是二少创作的最大动力!我们下期见!

Original: https://www.cnblogs.com/mofes/p/15042317.html
Author: 明天喝可乐
Title: JVM垃圾回收篇

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/589757/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【笔记整理】SpringBoot集成腾讯云短信

    前言 记录一下最近使用SpringBoot基础腾讯云里的短信产品功能的体验。 1、腾讯云申请开通短信服务。 2、配置短信内容:分别创建签名、模板和群发短信。 3、使用SpringB…

    Java 2023年6月5日
    082
  • 二、mybatis之数据输出

    上一篇我们做了一个入门案例,是我们做mybatis的基本步骤,不熟悉的可以回顾一下https://www.cnblogs.com/jasmine-e/p/15330355.html…

    Java 2023年6月16日
    080
  • java

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月15日
    072
  • SpringBoot定时任务-集成quartz实现定时任务(单实例和分布式两种方式)

    最为常用定时任务框架是Quartz,并且Spring也集成了Quartz的框架,Quartz不仅支持单实例方式还支持分布式方式。本文主要介绍Quartz,基础的Quartz的集成案…

    Java 2023年6月6日
    096
  • java项目命令启动 JAVA-jar包运行及日志输出

    一般情况下运行jar包,当前是可运行的jar包,直接命令 java -jar common.jar按下ctrl+C ,关闭当前ssh或者直接关闭窗口,当前程序都会退出。 我们在命令…

    Java 2023年5月29日
    0127
  • 通过PLSQL创建Database link,DBMS_Job,Procedure,实现Oracle跨库传输数据

    前一阵领导安排了一个任务:定时将集团数据库某表的数据同步至我们公司服务器的数据库,感觉比写增删改查SQL有趣,特意记录下来,希望能帮到有类似需求的小伙伴,如有错误也希望各位不吝指教…

    Java 2023年6月5日
    091
  • Mybatis简单入门–插入数据

    1. 开发环境 IDE:IDEA 构建工具:maven4.0.0 MySQL版本:8.0.11、 记得创建好数据库 Mybatis版本:3.5.7 MySQL不同版本的注意事项 驱…

    Java 2023年6月14日
    0100
  • 基于Javaweb,SSM火车订票系统

    一、项目简介 本项目为火车订票系统,主要分为管理员、普通用户二大角色。主要功能请看系统功能介绍。本系整个框架是基于ssm搭建,使用maven来管理依赖,使用MySQL作为数据库,使…

    Java 2023年6月8日
    083
  • Hive数据仓库工具基本架构和入门部署详解

    @ 概述 定义 本质 特点 Hive与Hadoop关系 Hive与关系型数据库区别 优缺点 其他说明 架构 组成部分 数据模型(Hive数据组织形式) Metastore(元数据)…

    Java 2023年6月5日
    077
  • 戏说领域驱动设计(廿五)——领域事件

    任何事物都在变化着包括领域驱动设计这门学问。Evans在首次提到DDD概念后,后来出现了陆续又出现了很多的专家与学者对其理论进行了扩充比如:”领域事件”、&…

    Java 2023年6月7日
    083
  • Java GC 日志详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt105 java GC日志可以通过 +PrintGCDet…

    Java 2023年5月29日
    084
  • 你说说对Java中SPI的理解吧

    前言 最近在面试的时候被问到SPI了,没回答上来,主要也是自己的原因,把自己给带沟里去了,因为讲到了类加载器的双亲委派模型,后面就被问到了有哪些是破坏了双亲委派模型的场景,然后我就…

    Java 2023年5月29日
    085
  • 第四篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabvie…

    Java 2023年6月7日
    074
  • springboot整合JPA

    spring-data-jpa:就是和数据库打交道,进行数据访问的。 一:步骤: 1.新建一个maven项目,新建一个数据库(数据库中可以没有表) 2.导入相关依赖 3.编写app…

    Java 2023年6月9日
    079
  • SpringBoot启动流程原理解析(二)

    在上一章我们分析了SpingBoot启动流程中实例化SpingApplication的过程。 return new SpringApplication(primarySources…

    Java 2023年6月5日
    083
  • mysql查询的时候没有加order by时的默认排序问题

    有时候我们执行MySQL查询的时候,查询语句没有加order by,但是发现结果总是已经按照id排序好了的,难道MySQL就是为了好看给我们排序 如上图数据,是我查询了语句 SEL…

    Java 2023年6月7日
    086
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球