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

  1. JVM、JRE和JDK的区别和联系

  2. JVM是什么?以及它的主要作用

  3. JVM的核心功能有哪些

  4. 类加载机制和过程

  5. 运行时数据区的逻辑结构

  6. JVM的内存模型

  7. 如何确定对象是垃圾

  8. 垃圾收集的算法有哪些

  9. 各种问世的垃圾收集器

  10. JVM调优的参数配置

线程私有内存区在类加载器编译某个class文件时就确定了执行时需要的“程序计数器”和“虚拟栈帧”等所需的空间,并且会伴随着当前执行线程的产生而产生,执行线程的消亡而消亡,因此“线程私有内存区”并不需要考虑内存管理和垃圾回收的问题。线程共享内存区在虚拟机启动时创建,被所有线程共享,是Java虚拟机所管理内存中最应该关注的和最大的一块。首先我们来一起看一下“线程共享内存区”的内存模型是什么样的?

六、JVM的内存模型

如图所示,JVM的内存结构分为堆和非堆两大块区域。

  • “非堆”就是上篇文章我们提到的方法区或叫元数据区,用来存储class类信息的。

  • “堆”是用来存储JVM各线程执行期间所创建的实例对象或数组的。堆区分为两大块,一个是Old区,一个是Young区。Young区分为两大块,一个是Survivor区(S0+S1),一块是Eden区S0和S1一样大,也可以叫From和To。

之所以这样划分,设计者的目的无非就是为了内存管理,也就是我们说的垃圾回收。

那么什么样的对象是垃圾?垃圾回收算法有哪些?目前常用的垃圾回收器又有哪些?这篇文章我们一起弄清楚这些问题和知识点。

七、如何确定一个对象是垃圾

要想进行垃圾回收,得先知道什么样的对象是垃圾。目前确认对象是否为垃圾的算法主要有两种:引用计数法和可达性分析法。

1、引用计数法:

  • 在对象中添加了一个引用计数器,当有地方引用这个对象时,引用计数器的值就加1,当引用失效的时候,引用计数器的值就减1。当引用计数器的值为0时,JVM就开始回收这个对象。

  • 对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任何指针对其引用,它就是垃圾。这种方法虽然很简单、高效,但是JVM一般不会选择这个方法,因为这个方法会出现一个弊端:当对象之间相互指向时,两个对象的引用计数器的值都会加1,而由于两个对象时相互指向,所以引用不会失效,这样JVM就无法回收。

2、可达性分析法:

  • 针对引用计数算法的弊端,JVM采用了另一种算法,以一些"GC Roots"的对象作为起始点向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,即可以进行垃圾回收。否则,证明这个对象有用,不是垃圾。

上图中的obj7和obj8虽然它们互相引用,但从GC Roots出发这两个对象不可达,所以会被标记为垃圾。JVM会把以下几类对象作为GC Roots:

  • (1) 虚拟机栈(栈帧中本地变量表)中引用的对象;

  • (2) 方法区中类静态属性引用的对象;

  • (3) 方法区中常量引用的对象;

  • (4) 本地方法栈中JNI(Native方法)引用的对象。

注:在可达性分析算法中不可达的对象,并不是直接被回收,这时它们处于缓刑状态,至少需要进行两次标记才会确定该对象是否被回收:

第一次标记:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记;

第二次标记:第一次标记后接着会进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法(该方法可将此对象与GC Roots建立联系)。在finalize()方法中没有重新与引用链建立关联关系的,将被进行第二次标记。

第二次标记成功的对象将真的会被回收,如果对象在finalize()方法中重新与引用链建立了关联关系,那么将会逃离本次回收,继续存活。

八、垃圾收集的算法有哪些

知道了如何JVM确定哪些对象是垃圾后,下面我们来看一下,面对这些垃圾对象,JVM的回收算法都有哪些。

1、 标记-清除算法(Mark-Sweep)

  • **第一步“标记”,**如下图所示把堆里所有的对象都扫描一遍,找出哪些是垃圾需要回收的对象,并且把它们标记出来。

  • 第二步“清除”,把第一步标记为“UnReference Object”(无引用或不可达)的对象清除掉,释放内存空间。

这种算法的缺点主要有两点:

(1) 标记和清除两个过程都比较耗时,效率不高

(2) 清除后会产生大量不连续的内存碎片空间,碎片空间太多可能会导致当程序后续需要创建较大对象时,无法找到足够连续的内存空间而不得不再次触发垃圾回收。

如果你觉得自己学习效率低,缺乏正确的指导,可以加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!
[Java架构群]
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的JAVA交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

2、 标记-复制算法(Mark-Copying)

将内存划分为两块区域,每次使用其中一块,当其中一块用满,触发垃圾回收的时候,将存活的对象复制到另一块上去,然后把之前使用的那一块进行格式化,一次性清除干净。

(清除前)

(清除后)

“标记-复制”算法的缺点显而易见,就是内存空间利用率低

3、 标记-整理算法(Mark-Compact)

标记整理算法标记过程仍然与"标记-清除"算法一样,但是后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

将所有存活的对象向一边移动,清理掉存活边界以外的全部内存空间。

结合这三种算法我们可以看到

  • “标记-复制”算法的优点是回收效率高,但空间利用率上有一定的浪费。

  • 而“标记-整理”算法由于需要向一侧移动等一系列操作,其效率相对低一些,但对内存空间管理上十分优异。

  • 因此,“标记-复制”算法适用于那些生命周期短、回收频率高的内存对象。

  • 而“标记-整理”算法适用于那些生命周期长、回收频率低,但注重回收一次内存空间得到足够释放的场景。

因此JVM的设计者将JVM的堆内存,分为了两大块区域Young区和Old区,Young区存储的就是那些生命周期短,使用一两次就不再使用的对象,回收一次基本上该区域十之有八的对象全部被回收清理掉,因此Young区采用的垃圾回收算法也就是“标记-复制”算法。Old区存储的是那些生命周期长,经过多次回收后仍然存活的对象,就把它们放到Old区中,平时不再去判断这些对象的可达性,直到Old区不够用为止,再进行一次统一的回收,释放出足够的连续的内存空间。

九、各种问世的垃圾收集器

鉴于Young区和Old区需要采用不同的垃圾回收算法,因此在JVM的整个垃圾收集器的演进各个时代里,针对Young区和Old区每个时代都是不同的垃圾收集机制。从JDK1.3开始到目前,JVM垃圾收集器的演进大体分为四个时代:串行时代、并行时代、并发时代和G1时代。

1、串行时代:Serial(Young区)+ Serial Old(Old区)

JDK3(1.3)的时候,大概是2000年左右,那个时代基本计算机都是单核一个CPU的,因此垃圾回收最初的设计实现也是基于单核单线程工作的。并且垃圾回收线程的执行相对于正常业务线程执行来说还是STW(stop the world)的,使用一个CPU或者一条收集线程去完成垃圾收集工作,这个线程执行的时候其它线程需要停止。

**串行收集器采用单线程stop-the-world的方式进行收集。**当内存不足时,串行GC设置停顿标识,待所有线程都进入安全点(Safepoint)时,应用线程暂停,串行GC开始工作,采用单线程方式回收空间并整理内存。单线程也意味着复杂度更低、占用内存更少,但同时也意味着不能有效利用多核优势。因此,串行收集器特别适合堆内存不高、单核甚至双核CPU的场合。

2、并行时代:Parallel Scavenge(Young区) + Parallel Old(Old区)

并行收集器是以关注吞吐量为目标的垃圾收集器,也是server模式下的默认收集器配置,对吞吐量的关注主要体现在年轻代Parallel Scavenge收集器上。

并行收集器与串行收集器工作模式相似,都是stop-the-world方式,只是暂停时并行地进行垃圾收集。年轻代采用复制算法,老年代采用标记-整理,在回收的同时还会对内存进行压缩。关注吞吐量主要指年轻代的Parallel Scavenge收集器,通过两个目标参数-XX:MaxGCPauseMills和-XX:GCTimeRatio,调整新生代空间大小,来降低GC触发的频率。并行收集器适合对吞吐量要求远远高于延迟要求的场景,并且在满足最差延时的情况下,并行收集器将提供最佳的吞吐量。

3、 并发时代:CMS(Old区)

并发标记清除(CMS)是以关注延迟为目标、十分优秀的垃圾回收算法,CMS是针对Old区的垃圾回收实现。

老年代CMS每个收集周期都要经历:初始标记、并发标记、重新标记、并发清除。其中,初始标记以STW的方式标记所有的根对象;并发标记则同应用线程一起并行,标记出根对象的可达路径;在进行垃圾回收前,CMS再以一个STW进行重新标记,标记那些由mutator线程(指引起数据变化的线程,即应用线程)修改而可能错过的可达对象;最后得到的不可达对象将在并发清除阶段进行回收。值得注意的是,初始标记和重新标记都已优化为多线程执行。CMS非常适合堆内存大、CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器。

- 但CMS有以下两个缺陷:

  • (1)由于它是标记-清除不是标记-整理,因此会产生内存碎片,Old区会随着时间的推移而终究被耗尽或产生无法分配大对象的情况。最后不得不通过底层的担保机制(CMS背后有串行的回收作为兜底)进行一次Full GC,并进行内存压缩。

  • (2)由于标记和清除都是通应用线程并发进行,两类线程同时执行时会增加堆内存的占用,一旦某一时刻内存不够用,就会触发底层担保机制,又采用串行回收进行一次STW的垃圾回收。

4、G1时代:Garbage First

G1收集器时代,Java堆的内存布局与就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。

如上图所示,每一个Region(分区)大小都是一样的,1~32M之间的数值,但必须是2的指数。设置Region大小通过以下参数:-XX:G1HeapRegionSize=M。G1收集器的原理或特点主要有以下三点:

(1)内存逻辑上仍保留的分代的概念,每一个Region同一时间要么被标记为新生代,要么被标记为老年代,要么处于空闲;

(2)整体上采用了“标记-整理算法”,不会产生内存碎片

(3)可预测的停顿,G1整体采用的策略是“筛选回收”,也就是回收前会对各个待回收的Region的回收价值和成本进行排序,根据G1配置所期望的回收时间,选择排在前面的几个Region进行回收。

其实之所以叫G1(Garbage First)就是因为它优先选择回收垃圾比较多的Region分区。整体G1的垃圾回收工作步骤分为:初始标记、并发标记、最终标记和筛选回收。

5、ZGC:Zero GC

这篇文章简单提一下这个最新问世的垃圾收集器,之所以叫“Zero GC”是因为它追求的是更低的GC停顿时间,追求的目标是:支持TB级堆内存(最大4T)、最大GC停顿10ms。

JDK11新引入的ZGC收集器,不管是物理上还是逻辑上,ZGC中已经不存在新老年代的概念了会分为一个个page,当进行GC操作时会对page进行压缩,因此没有碎片问题。由于其是JDK11和只能在64位的linux上使用,因此目前用得还比较少。

十、总结

一直想整理出一份完美的面试宝典,但是时间上一直腾不开,这套一千多道面试题宝典,结合今年金三银四各种大厂面试题,以及 GitHub 上 star 数超 30K+ 的文档整理出来的,我上传以后,毫无意外的短短半个小时点赞量就达到了 13k,说实话还是有点不可思议的。

一千道互联网 Java 工程师面试题

内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、SpringBoot、SpringCloud、RabbitMQ、Kafka、Linux等技术栈(485页)

初级—中级—高级三个级别的大厂面试真题

阿里云——Java 实习生/初级

List 和 Set 的区别 HashSet 是如何保证不重复的

HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?

HashMap 的扩容过程

HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?

对象的四种引用

Java 获取反射的三种方法

Java 反射机制

Arrays.sort 和 Collections.sort 实现原理 和区别

Cloneable 接口实现原理

异常分类以及处理机制

wait 和 sleep 的区别

数组在内存中如何分配

答案展示:

美团——Java 中级

BeanFactory 和 ApplicationContext 有什么区别

Spring Bean 的生命周期

Spring IOC 如何实现

说说 Spring AOP

Spring AOP 实现原理

动态代理(cglib 与 JDK)

Spring 事务实现方式

Spring 事务底层原理

如何自定义注解实现功能

Spring MVC 运行流程

Spring MVC 启动流程

Spring 的单例实现原理

Spring 框架中用到了哪些设计模式

为什么选择 Netty

说说业务中,Netty 的使用场景

原生的 NIO 在 JDK 1.7 版本存在 epoll bug

什么是 TCP 粘包/拆包

TCP 粘包/拆包的解决办法

Netty 线程模型

说说 Netty 的零拷贝

Netty 内部执行流程

答案展示:

蚂蚁金服——Java 高级

题 1:

  1. jdk1.7 到 jdk1.8 Map 发生了什么变化(底层)?

  2. ConcurrentHashMap

  3. 并行跟并发有什么区别?

  4. jdk1.7 到 jdk1.8 java 虚拟机发生了什么变化?

  5. 如果叫你自己设计一个中间件,你会如何设计?

  6. 什么是中间件?

  7. ThreadLock 用过没有,说说它的作用?

  8. Hashcode()和 equals()和==区别?

  9. mysql 数据库中,什么情况下设置了索引但无法使用?

  10. mysql 优化会不会,mycat 分库,垂直分库,水平分库?

  11. 分布式事务解决方案?

  12. sql 语句优化会不会,说出你知道的?

  13. mysql 的存储引擎了解过没有?

  14. 红黑树原理?

题 2:

  1. 说说三种分布式锁?

  2. redis 的实现原理?

  3. redis 数据结构,使⽤场景?

  4. redis 集群有哪⼏种?

  5. codis 原理?

  6. 是否熟悉⾦融业务?记账业务?蚂蚁⾦服对这部分有要求。

好啦~展示完毕,大概估摸一下自己是青铜还是王者呢?

前段时间,在和群友聊天时,把今年他们见到的一些不同类别的面试题整理了一番,于是有了以下面试题集,也一起分享给大家~

如果你觉得这些内容对你有帮助,可以加入csdn进阶交流群,领取资料

基础篇


JVM 篇


MySQL 篇



Redis 篇




由于篇幅限制,详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

需要的小伙伴,可以一键三连,下方获取免费领取方式!

十个问题教你弄清JVMGC,细致入微全是精华!!(建议收藏)相关推荐

  1. 箱线图怎么看_K线的48种不同类型全解(建议收藏),教你怎么看懂K线图

    ID:K线助手 来源:公众号 链接:K线的48种不同类型全解(建议收藏),教你怎么看懂K线图 中国起步较晚,1990年我国股市开市时直接起用了K线,但对K线的研究.使用一直局限于日本人的研究成果,主要 ...

  2. YOLO系列算法精讲:从yolov1至yolov4的进阶之路(呕心沥血2万字超全整理,建议收藏!)

    从刚开始接触YOLO到现在也已经有大半年时间了,中间也陆陆续续接触过其它网络.最近又抽时间研究了一下YOLOv4. 因此,趁此机会,将yolov1到yolov4进行一个全面的整理和总结,希望对即将入坑 ...

  3. 从Java程序员进阶为架构师,全套16张图概括最全技能!建议收藏!

    如何从程序员进阶到架构师?今天完整的把我积累的经验和技能分享给大家! 作者:陈睿|优知学院创始人 数据结构+算法=程序 数据是一切能输入到计算机的信息总和,结构是指数据之间的关系,数据结构就是将数据及 ...

  4. 关于《数据仓库知识体系》的超全指南(建议收藏)

    文章很长,前言一定要看 拥有本篇文章,意味着你拥有一本完善的书籍,本篇文章整理了数据仓库领域,几乎所有的知识点,文章内容主要来源于以下几个方面: 源于资深数据仓库工程师的交流讨论,如<sql行转 ...

  5. 如何成功发表一篇论文(最全攻略) ——建议收藏

    学术论文到底怎么写才能发表?此篇内容手把手教大家如何快速的写好科研论文并顺利发表. 内容针对的是论文的写作要求,需要毕业论文的朋友也可以参考写作方法,内容包括了:从如何调研确定topic,如何多快好省 ...

  6. 触发器及其应用实验报告总结_双面喷绘材料的分类及其应用,超全总结!(建议收藏)...

    ▲ 东川 | 点击图片获取更多信息▲ 东川 | 点击图片获取更多信息 双面喷绘材料,有适合水性机器喷的双面摭光画布,有适合弱溶剂和UV喷绘的PVC双喷.PET双喷.双喷网格布.双面牛筋布,它们有个共同 ...

  7. 微信多开txt_1分钟教你如何实现微信多开!建议收藏!

    近期都知道腾讯系的社交软件,例如QQ.微信已经在中国深入人心,这两个软件基本每个人都在使用,但是QQ是可以多开的,微信却只能开一个. 现在很多人都是一个工作微信,一个生活微信.如何才能在电脑上同时登录 ...

  8. 捡到的苹果手机怎么解id锁_苹果手机换id通讯录没了怎么恢复?超全教程,建议收藏!...

    苹果手机换id通讯录没了怎么恢复?最近小编在自己的iPhone上登录了朋友的Apple ID,在切换账号以后发现自己手机里的通讯录都不见了,平常和客户沟通比较多,这么多号码不见了该怎么恢复? 虽然当下 ...

  9. 半小时学会在Win10上部署K8S,玩转云原生【全干货,建议收藏】

    01 引子 起因也是因为最近刚好重做了系统,把win10从home版升级到了专业版,可以愉快的安装docker destop 而不需要借助 docker toolbox了. 这个使用体验的提升真的是很 ...

最新文章

  1. gdb coredump
  2. 正则表达式——全部符号解释(详解)
  3. 用诸葛孔明的智慧,读懂新型数据中心的“四新”机遇与产业逻辑
  4. Linux 下如何处理包含空格和特殊字符的文件名
  5. protobuf---messge嵌套get set
  6. JWT【JSON Web Token】 简述
  7. 对比一段ADC键值读取的代码
  8. Oracle count函数原理,oracle count函数
  9. glassfish3新建domain
  10. SQL语句优化—in,not in,exists,not exists, left join...on
  11. rocketMq消息重复消费问题
  12. mysql 转字符串 blob_BLOB转换为字符串或图像/ PHP或SQL
  13. linux系统下载r软件安装,Linux安装R语言包
  14. Scan2CAD pro中文版
  15. 线程优先级的设定pthread_setschedparam
  16. node_注册页面+连接数据库+加密
  17. tcprewrite批量修改报文ip地址二
  18. mysql修改表结构会锁表吗_MYSQL完美解决生产环境改表结构锁表问题
  19. sae wpa3加密方式_WPA3:四大安全新特性技术分析
  20. 转SISD、MIMD、SIMD、MISD计算机的体系结构的Flynn分类法

热门文章

  1. Unity 2D图片外轮廓描边和内发光的Shader实现
  2. 学习之道。 文/江湖一剑客
  3. splint选项介绍
  4. DBeaver连接phoenix
  5. (九)论文阅读 | 目标检测之GA
  6. Thinkphp 微信公众号开发3-微信登录源码
  7. 铅酸蓄电池单格最高与最低电压
  8. 《java入门第一季》之Date类案例,算一算你的恋爱纪念日
  9. 计算机专业与英语关系大不大,计算机专业英语学习的策略.doc
  10. 稳若磐石的焱融 SaaS 服务平台背后,是数据生态的崛起