每日六道java新手入门面试题,通往自由的道路--JVM

目录
  • 1. JVM是如何判断对象是否可回收
  • 2. 你知道有什么垃圾回收的常见算法吗?
  • 3. 你知道有什么垃圾收集器吗?
  • 4. 那你知道什么时候才会触发Full GC
  • 5. JVM中四种引用你有了解过吗?
  • 6. 说说你知道的几种主要的JVM参数
    • 1.堆设置
    • 2.收集器设置
    • 3.并行收集器设置
    • 4.并发收集器设置
    • 5.JVM 调优的参数
  • 总结

1. JVM是如何判断对象是否可回收

垃圾收集器在做垃圾回收的时候,首先需要判断一个对象是存活状态还是死亡状态,死亡的对象将会被标识为垃圾数据并等待收集器进行清除。

而判断一个对象是否为可回收状态的常用算法有两个:引用计数器法和可达性分析算法。

  • 引用计数器法:

在 Java 中,引用和对象是有关联的,通过引用计数来判断一个对象是否可以回收。它在创建对象时关联一个与之相对应的计数器,当此对象被使用时加 1,相反销毁时 -1。当此计数器为 0 时,则表示此对象未使用,可以被垃圾收集器回收。其优点是垃圾回收比较及时,实时性比较高,只要对象计数器为 0,则可以直接进行回收操作;而缺点是无法解决循环引用的问题。

  • 可达性分析算法:

主要是从GC Root的对象为起点出发,然后开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Root之间没有任何引用链的时候,代表这个对象不可以用,判断为垃圾,就会被GC回收。

在 java 中可以作为 GC Roots 的对象有以下几种:

  • 虚拟机栈中引用的对象
  • 方法区类静态属性引用的对象
  • 方法区常量池引用的对象
  • 本地方法栈 JNI 引用的对象

2. 你知道有什么垃圾回收的常见算法吗?

标记清除法:

分为标记–清除两个阶段,首先先标记出所有需要回收的对象,然后在标记完成后统一清除回收所有被标记的对象。

它可能产生的问题呢标记清除后,产生一些大量不连续的内存碎片,导致可能以后后续的大内存找不到足够的连续内存再导致提前又发生一次垃圾收集

标记整理法:

基本步骤和标记清除类似,但是多了一步整理的步骤,让所有村后的对象都向一端移动,然后清除掉不需要的内存。

它解决了内存碎片的问题,但是需要频繁的移动存活的对象,效率就比较低了。

复制算法:

将可用的内存分为一半,每次只使用一个区域。将需要存活的对象复制到另一个对象中去。

这种方法也是可以解决了内存碎片问题,但是内存对半分了,而且对象存活率高的对象需要频繁复制。

基于前面的算法的话,JVM采用一个分代算法的形式:

对于JVM的堆来说分为了新生代和老年代两个区域,而新生代也还分了eden区和两个幸存区,他们比例是8:1:1,

对于新生代来说采用了复制算法,因为对于新生代来说每次垃圾回收的存活的对象是比较少的,所以采用复制算法较好,而老年代的话,则采用了标记整理法。

  • 首先对象会先分配在eden区,
  • 然后再新生代空间不足时,会发生一次minor gc算法将存活的对象复制到幸存区s1中,并使存活的对象的年龄加1,然后s1和s0交换,。
  • 在对象寿命超过阈值最大15时,就会晋升至老年代。
  • 而当老年代的空间不足时,会先尝试触发一次minor gc,如果空间还是不足的话。就会出发full gc ,而此时的stw会更长。

3. 你知道有什么垃圾收集器吗?

常见的垃圾收集器有:其中用于回收新生代的收集器有Serial、PraNew、Parallel Scavenge,而回收老年代的收集器有Serial Old、Parallel Old、CMS,最后还有一个可以用于回收整个Java堆的G1收集器。

作用于新生代的:

  • Serial 收集器属于最早期的垃圾收集器,也是 JDK 1.3 版本之前唯一的垃圾收集器。它是单线程的垃圾收集器,采用复制算法,其意味着单线程是指在进行垃圾回收时所有的工作线程必须暂停,直到垃圾回收结束为止。

特点是简单和高效,并且本身的运行对内存要求不高,因此它在客户端模式下使用的比较多。

  • sParNew 收集器实际上是 Serial 收集器的多线程并行版本,也是采用复制算法。
  • Parallel Scavenge 收集器和 ParNew 收集器类似,它也是一个并行运行的垃圾回收器;不同的点在于该收集器关注的侧重点是实现一个可以控制的吞吐量。它的计算公式是:用户运行代码的时间 / (用户运行代码的时间 + 垃圾收集的时间)。比如用户运行的时间是 8 分钟,垃圾回收运行的时间是 2 分钟,那么吞吐量就是 80%。Parallel Scavenge 收集器追目标就是达到一个可控制的吞吐量,高吞吐量可以最高效率地利用CPU时候,尽快地完成程序的运算任务。

作用于老年代的:

  • Serial Old 收集器为 Serial 收集器的老年代版本,而 Parallel Old 收集器是 Parallel Scavenge 收集器的老年代版本。两者都是在老年代中采用这标记—— 整理算法。
  • CMS(Concurrent Mark Sweep)以获取最短回收停顿时间为目标,与Parallel Scavenge 收集器不同,是基于标记 —— 清除算法实现。它强调的是提供最短的停顿时间,因此可能会牺牲一定的吞吐量。它主要应用在 Java Web 项目中,它满足了系统需要短时间停顿的要求,以此来提高用户的交互体验。CMS 工作机制相比其他的垃圾收集器来说更复杂。整个过程分为以下 4 个阶段:
    • 初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象
    • 并发标记(CMS concurrent mark):进行 GC Roots Tracing
    • 重新标记(CMS remark):修正并发标记期间的变动部分并发清除
    • (CMS concurrent sweep):清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。

作用于整个Java堆包括新生代和老年代的。

  • Garbage First(简称 G1)收集器是历史发展的产物,也是一款更先进的垃圾收集器,主要面向服务端应用的垃圾收集器,是基于基于标记-整理算法实现,不产生内存碎片。它将内存划分为多个 Region 分区,回收时则以分区为单位进行回收,这样它就可以用相对较少的时间优先回收包含垃圾最多区块。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。从 JDK 9 之后也成了官方默认的垃圾收集器,官方也推荐使用 G1 来代替选择 CMS 收集器。

4. 那你知道什么时候才会触发Full GC

1.在老年代空间不足的时候:

老年代空间只有在新生代对象发生minor Gc转入或者是直接创建为大对象、大数组时出现空间不足的现象,当JVM执行Full GC后空间仍然不足,则抛出如下错误:java.lang.OutOfMemoryError: Java heap space。

解决措施:尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

2.在我们程序中直接调用了System.gc, 也会直接出发Full GC。

3.在永久代空间满

永久代中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,永久代空间可能会被占满,在未配置的时候采用这CMS垃圾收集器的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:java.lang.OutOfMemoryError: PermGen space。

解决措施:可采用的方法为增大永久代空间或转为使用CMS GC。

4.在CMS垃圾收集器出现promotion failed(晋升失败)和concurrent mode failure(并发模式故障)

对于如果我们采用CMS垃圾收集器进行老年代GC的程序而言,我们就需要主要在GC日志中是否有晋升失败和并发模式故障两种状况,当这两种状况出现时可能会触发Full GC:

晋升失败(promotion failed) 是在新生代进行Minor GC时,幸存区中放不下、而对象只能放入老年代,而此时老年代也放不下造成的。

concurrent mode failure是CMS转悠的错误,即并发清楚线程和工作线程同时工作,清理出来老年代的空间不足以存放由新生代晋升到老年代的对象。

解决措施:减少年轻代大小,避免放入老年代时需要分配大的空间,同时调整触发Full GC时的比率以及将触发CMS GC的阀值适当增大

5. JVM中四种引用你有了解过吗?

  • 强引用:垃圾收集器不会回收被强引用的对象。

在 Java 中最常见的就是强引用, 把一个对象赋给一个引用变量,这个引用变量就是一个强引用。即在我们写类似这样User user = new User(),我们new出来的user对象就是一个强引用了!

当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。

  • 软引用:在没有被强引用对象,当系统要发生内存溢出的异常之前,会将其列为回收范围,进行第二次回收。

软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。

  • 弱引用:具有弱引用的对象拥有更短暂的生命周期。在没有被强引用对象,只能存活在下一次垃圾收集器前。无论内存够不够。

弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。

  • 虚引用:无法通过虚引用取得一个对象实例,设置虚引用的目的是为了能在这个对象被垃圾收集器回收时收到一个通知。 虚引用的主要作用是跟踪对象被垃圾回收的状态。

6. 说说你知道的几种主要的JVM参数

1.堆设置

  • -Xms:初始堆大小
  • -Xmx:最大堆大小
  • -XX:NewSize=n:设置新生代大小
  • **-XX:NewRatio=n:**设置年轻代和年老代的比值。如:为3,表示新生代与老年代比值为1:3,新生代占整个新生代老年代和的1/4
  • -XX:SurvivorRatio=n:新生代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个新生代的1/5
  • -XX:MaxPermSize=n:设置持久代大小

2.收集器设置

  • -XX:+UseSerialGC:设置串行收集器
  • -XX:+UseParallelGC:设置并行收集器
  • -XX:+UseParalledlOldGC:设置并行老年代收集器
  • -XX:+UseConcMarkSweepGC:设置并发收集器

3.并行收集器设置

  • -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
  • -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
  • -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

4.并发收集器设置

  • -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
  • -XX:ParallelGCThreads=n:设置并发收集器新生代收集方式为并行收集时,使用的CPU数。并行收集线程数。

5.JVM 调优的参数

  • **-Xms2g:**初始化推大小为 2g;
  • **-Xmx2g:**堆最大内存为 2g;
  • **-XX:NewRatio=4:**设置年轻的和老年代的内存比例为 1:4;
  • **-XX:SurvivorRatio=8:**设置新生代 Eden 和 Survivor 比例为 8:2;
  • **–XX:+UseParNewGC:**指定使用 ParNew + Serial Old 垃圾回收器组合;
  • **-XX:+UseParallelOldGC:**指定使用 ParNew + ParNew Old 垃圾回收器组合;
  • **-XX:+UseConcMarkSweepGC:**指定使用 CMS + Serial Old 垃圾回收器组合;
  • **-XX:+PrintGC:**开启打印 gc 信息;
  • **-XX:+PrintGCDetails:**打印 gc 详细信息。

总结

本篇文章就到这里了,如果这篇文章对你也有所帮助,希望您可以多多关注我们的更多内容!

(0)

相关推荐

  • 每日几道java新手入门面试题,通往自由的道路

    目录 1.请你说一下什么是面向对象? 2.请你简述一下面向对象的三个基本特征? 3.为什么说 Java 是一种半解释半编译的程序设计语言呢? 4.请你说一下Java中的8大基本类型是那些? 5.请你讲讲抽象类和接口有什么区别? 6.请判断当一个对象被当作参数传递给一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 7.请你说一下JVM/JRE/JDK的区别? 8.请你说一下方法重载和方法重写的区别? 9.请你说一下List接口和Set接口的区别? 1

  • 每日六道java新手入门面试题,通往自由的道路--多线程

    目录 1. 你可以讲下进程与线程的区别?为什么要用多线程? 2. 什么是上下文切换? 3. 说说你知道的几种创建线程的方式 4. 昨天你讲到创建线程后使用start方法去调用线程,为什么run方法不行呢?有什么区别? 5. 你知道你开启一个线程后,它的状态有那些吗? 6. 既然讲到超时方法,那你讲下sleep和wait的区别和他们需要怎样唤醒 总结: 1. 你可以讲下进程与线程的区别?为什么要用多线程? 进程:进程是程序的一次执行过程,是系统运行程序的基本单位. 线程:单个进程中执行中每个任务就

  • 三道java新手入门面试题,通往自由的道路--锁+Volatile

    目录 1. 你知道volatile是如何保证可见性吗? 小结: 2. 悲观锁和乐观锁可以讲下你的理解吗? 3. 你还知道什么其他的锁吗? 总结 1. 你知道volatile是如何保证可见性吗? 我们先看一组代码: public class VolatileVisibleDemo { public static boolean initFlag = false; public static void main(String[] args) { new Thread(new Runnable() {

  • 每日六道java新手入门面试题,通往自由的道路

    目录 1. 面试第一步,自我介绍. 2. 请你简述下对面向对象的理解,面向对象和面向过程的区别? 3. 那你再讲下面向对象的特征有哪些方面 4. 请问:我们是否可以继承 String类? 5. 我再问下final.finally.finalize这三者有什么区别吗? 6. 请讲下String和 StringBuilder.StringBuffer之间的区别? 总结 1. 面试第一步,自我介绍. 这个自我介绍,在整个面试当中可以说是第一步,如果你能把你想说的重点说出来,把面试官带到你准备好的技术点

  • 每日六道java新手入门面试题,通往自由的道路--线程池

    目录 1. 你知道线程池吗?为什么需要使用线程池? 小结: 2. 你知道有多少种创建线程池的方式 3. 线程池的五种状态你有了解吗? 4. 你知道ThreadPoolExecutor的构造方法和参数吗 5. 你可以说下线程池的执行过程原理吗 6. 能否写一个简单线程池的demo? 总结 1. 你知道线程池吗?为什么需要使用线程池? 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源. 而在Java中, JVM 中每创建和销毁线程就需要资源和时间的损耗了,

  • 三道java新手入门面试题,通往自由的道路--JVM

    目录 1. 你知道JVM内存模型吗? 2. 你知道重排序是什么吗? 3. happens-before是什么,和as-if-serial有什么区别 总结 1. 你知道JVM内存模型吗? 在Java的并发中采用的就是JVM内存共享模型即JMM(Java Memory Model),它其实是是JVM规范中所定义的一种内存模型,跟计算机的CPU缓存内存模型类似,是基于CPU缓存内存模型来建立的,Java内存模型是标准化的,屏蔽掉了底层不同计算机的区别. 那我们先来讲下计算机的内存模型: 其实早期计算机

  • 三道java新手入门面试题,通往自由的道路--多线程

    目录 1. 你知道线程安全问题吗? 2. 那如何解决线程安全问题呢? 3. 那你讲下死锁是什么吧? 总结 1. 你知道线程安全问题吗? 线程安全问题:一般指在多线程模式下,多个线程对同一个共享数据进行操作时,第一个线程还没来得及更新共享数据,从而导致另外一个线程没得到最新的数据,并更新数据,从而产生线程安全问题.比较常见的场景有买票. 我举个例子吧: 需求:比如买周杰伦演唱会的门票,此时有三个窗口同时卖总共100张票.窗口就是线程对象,而100张票的资源,此时就相当于多个线程去抢占cpu的资源去

  • 每日六道java新手入门面试题,通往自由的道路第二天

    目录 1. 你可以讲下你对String类有什么其他的了解吗? 2. == 和 equals 的区别 3. String s= new String("nz")创建了几个字符串对象? 4. 你可以讲下JVM的运行时数据区或者说内存结构吗? 5. 类加载过程 6. 而其中类加载器是什么,那有哪些呢? 总结 1. 你可以讲下你对String类有什么其他的了解吗? 在看String的源码过程中,可以发现String 内部实际存储结构为 char数组,在String中有几个比较重要的构造函数:

  • 每日六道java新手入门面试题,通往自由的道路--JVM

    目录 1. JVM是如何判断对象是否可回收 2. 你知道有什么垃圾回收的常见算法吗? 3. 你知道有什么垃圾收集器吗? 4. 那你知道什么时候才会触发Full GC 5. JVM中四种引用你有了解过吗? 6. 说说你知道的几种主要的JVM参数 1.堆设置 2.收集器设置 3.并行收集器设置 4.并发收集器设置 5.JVM 调优的参数 总结 1. JVM是如何判断对象是否可回收 垃圾收集器在做垃圾回收的时候,首先需要判断一个对象是存活状态还是死亡状态,死亡的对象将会被标识为垃圾数据并等待收集器进行

  • 三道MySQL新手入门面试题,通往自由的道路

    目录 1. 讲讲你认识MySQL锁吧 2. 你知道什么是事务.四大特性.隔离级别吗? 3. MyISAM 和 InnoDB 存储引擎的区别 总结 1. 讲讲你认识MySQL锁吧 对于数据库来讲,读写都是非常频繁的吧,在并发量来的时候,在进行读写操作时,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,所以锁就可以在一定限度保护它的一致性. 首先我们可以按锁的粒度分: 1.表级锁:它上锁是锁住的整张表,当下一个事务来访问的时候,必须等到当前事务把锁释放了,才能对表进行操作访问. 特点:表

随机推荐