HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
随笔
关于作者
  • 《LearnJavaToFindAJob》

    • 导读

    • 【初级】6~12k档

      • Java基础

      • JVM

        • JVM面试题(一)
        • JVM面试题(二)
      • 牛客网题库

      • MySQL

      • Linux

      • 计算机网络

      • 操作系统

      • Java框架

    • 【中级】12k-26k档

    • 【高级】26k+档

    • 大厂面试题

    • 求职建议

    • 面经

  • LearnJavaToFindAJob
  • 【初级】6~12k档
  • JVM
#JVM #面试题二
码农阿雨
2022-06-02
目录

JVM面试题(二)

# 1、怎么查看服务器默认的垃圾回收器是哪一个?

可以使用一个参数:-XX:+PrintCommandLineFlags可以打印所有的参数,包括使用的垃圾回收器。

以下是演示:

java -XX:+PrintCommandLineFlags -version

Windows:

C:\Users\HaC> java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=266928960 -XX:MaxHeapSize=4270863360 -XX:+PrintCommandLineFlags -XX:+UseCompress
edClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

Linux:

[root@GZSB-CJB-SHH1-14-GEMINI-0 ~]# java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=261339776 -XX:MaxHeapSize=4181436416 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

可以看到是使用了 UseParallelGC

还可以使用 jmap -heap 进程id 命令查看收集器,还可以查看新生代、老年代的空间大小。

[root@VM_0_12_centos ~]# jmap -heap 19505

Attaching to process ID 19505, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11

using thread-local object allocation.
Garbage-First (G1) GC with 1 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 268435456 (256.0MB)
   NewSize                  = 1363144 (1.2999954223632812MB)
   MaxNewSize               = 160432128 (153.0MB)
   OldSize                  = 5452592 (5.1999969482421875MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 1048576 (1.0MB)

Heap Usage:
G1 Heap:
   regions  = 256
   capacity = 268435456 (256.0MB)
   used     = 66499440 (63.41880798339844MB)
   free     = 201936016 (192.58119201660156MB)
   24.772971868515015% used
G1 Young Generation:
Eden Space:
   regions  = 18
   capacity = 74448896 (71.0MB)
   used     = 18874368 (18.0MB)
   free     = 55574528 (53.0MB)
   25.35211267605634% used
Survivor Space:
   regions  = 1
   capacity = 1048576 (1.0MB)
   used     = 1048576 (1.0MB)
   free     = 0 (0.0MB)
   100.0% used
G1 Old Generation:
   regions  = 46
   capacity = 58720256 (56.0MB)
   used     = 46576496 (44.41880798339844MB)
   free     = 12143760 (11.581192016601562MB)
   79.31929997035435% used

34372 interned Strings occupying 3886072 bytes.

Garbage-First (G1) GC with 1 thread(s) ,可以看到是使用了 G1 垃圾收集器。Eden Space、Survivor Space、G1 Old Generation分别说明了Eden区、Survivor区、老年代的大小。

常用的命令行工具还有:jps、jstat、jinfo、jmap、jstack。而更多的可视化工具如jconsole、visualVM等暂不介绍,大家有兴趣请参阅相关文档。查看新生代内存占用、老年代内存占用、其他区内存占用和GC等四大方面的指标。

# 2、为什么要有GC,哪些内存对象需要回收?

对于一个Java开发者来说,了解过Java内存区域的都知道,Java内存区域分了堆、栈、程序计数器等等。

Java的程序计数器,栈内存 ,他们随线程生,随线程灭,方法结束后内存也就回收了。

一个字符串“abc”已经进入常量池,但是当前系统没有任何一个String对象引用了做“abc”的字面量,那么,如果发生垃圾回收并且有必要时,“abc”就会被系统移出常量池。

常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

当Java虚拟机发现内存资源紧张的时候,就会自动地去清理无用变量所占用的内存空间,为我们的程序提升更高的性能。

# 3、如何判断对象需要回收?

一般常见的两种回收判断算法:

# 2.1、 引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1。

任何时刻计数器为0的对象就是不可能再被使用的。

该方法实现简单,效率高,但是它很难它很难解决对象之间相互循环引用的问题。比如图中的 Object3 和Object4相互引用,引用计数不可能为0,虽然它们已经没有被Root引用了。

所以,大多数jvm判断对象是否存活基本并没有采取该方法。

# 2.2、可达性分析算法(根搜索算法)

这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain)。

当一个对象到GC Roots没有任何引用链相连时(不可达)则证明此对象是不可用的。

要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

被认为GC Roots的有以下几种:

  • 虚拟机栈中引用的对象
  • 方法区中静态属性、常量引用的对象
  • Native方法引用的对象

# 4、JVM中一次完整的GC流程是怎样的

GC是垃圾收集的意思,Java语言没有提供释放已分配内存的显示操作方法。开发者不用担心内存管理,因为垃圾收集器会自动进行管理。

首先,分代收集法是目前虚拟机(包括HotSpot VM)收集器都是采用该方法。所以一般是回答分代收集算法的垃圾回收过程。

  • # 分代收集算法的GC过程:

    (1)在年轻代中,Eden区提供堆内存如果满了,Eden进行MinorGC,将存活的对象→from ,Eden区清空;

    (2)Eden区再次满, Eden 区和 from 区同时进行 Minor GC,把存活对象放入 to 区,Eden和from 同时清空;

    如果在to区中的对象仍然存活,则把对象标志 +1。

    (3)重复(2)的操作, 某些对象在反复 Survive 15 次后,或者Eden+from 的存活对象 > to ,这些对象就只能放到老年代了,如果老年代放不下了,就进行Full GC);

    (4)当 Old 区也被填满时,进行 Full GC,对 Old 区进行垃圾回收。

    可以通过参数 SurvivorRatio 手动配置 Eden 区和单个 Survivor 区的比例,默认为 8。可以通过参数–XX:SurvivorRatio 来设定,即将堆内存中年轻代划分为8:1:1

# 5、GC监控怎么看?

jdk自带的命令:

  • jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
  • jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
  • jmap,JVM Memory Map命令用于生成heap dump文件
  • jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
  • jstack,用于生成java虚拟机当前时刻的线程快照。
  • jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。

工具:

jdk自带监控工具:jconsole和jvisualvm,位于bin目录

# 6、有没有遇到过OutOfMemoryError和StackOverflowError,这两者的区别是什么,怎么解决?

OOM问题。

1、OutOfMemoryError 常见场景:

  • Java.lang.OutOfMemoryError: PermGen space

    程序中使用了大量的jar或class,使java虚拟机装载类的空间不够。 **解决:**增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,如: -XX:PermSize=64M -XX:MaxPermSize=128m

  • java.lang.OutOfMemoryError: Java heap space java虚拟机创建的对象太多,在进行垃圾回收之前,虚拟机分配的到堆内存空间已经用满了。

    **解决:**设置堆的起始大小、最大空间,如-Xms256m -Xmx1024m

  • java.lang.OutOfMemoryError: unable to create new native thread

    环境提供的服务器配置偏低,而项目本身为了性能,大量的使用的线程,因为线程的开辟比new Object是需要很大空间的。创建线程数超过了操作系统的限制。

    解决:减少程序的线程数量;或者增大服务器的系统线程限制数量。

2、StackOverflowError 常见场景:

StackOverflowError 是一个java中常出现的错误:在jvm运行时的数据区域中有一个java虚拟机栈,当执行java方法时会进行压栈弹栈的操作。在栈中会保存局部变量,操作数栈,方法出口等等。jvm规定了栈的最大深度,当执行时栈的深度大于了规定的深度,就会抛出StackOverflowError错误。

  • java.lang.StackOverflowError

    出现这种异常,大多是由于循环调用

典型的例子:

public class StackOverFlowErrorDemo {
    public static void HaC(){
        HaC();
    }
    public static void main(String[] args) {
        HaC();
    }
}

解决方案:

​ 把递归调用函数改用while或者for循环来实现 。

​ 增大栈的大小值。(如 -Xss100m )

​ 改用堆内存。(把局部变量改成全局静态变量)

​

# 7、怎么看死锁的线程?

Jconsole Jconsole是JDK自带的图形化界面工具,使用JDK给我们的的工具JConsole,可以通过打开cmd然后输入jconsole打开。

jstack

通过jstack命令,可以获得线程的栈信息。死锁信息会在非常明显的位置(一般是最后)进行提示。

演示一下:

1、用jps查找当前Java进程:

[root@VM-8-8-centos ~]# jps
9368 Jps
15850 jar
3244 jar

2、 jstack -l 15850 查看进程的堆栈情况,拉到最后就有死锁的信息了 :

# 8、MinorGC,MajorGC、FullGC都什么时候发生?

MinorGC在年轻代空间(Eden区)不足的时候发生。

MajorGC指的是老年代的GC,出现MajorGC一般经常伴有MinorGC。

但是新的虚拟机已经没有MajorGC这一说法了。Major GC的速度一般会比Minor GC慢10倍以上。

FullGC有以下几种情况

FullGC 是清理整个堆空间—包括年轻代和老年代、永久代(如果有)

​ (1)调用System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足

(3)方法区空间不足

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、survivor space1(From Space)区向survivor space2(To Space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

# 9、三色标记

三色标记是一种并发标记算法,用于在不停顿应用线程的情况下遍历对象图。

三色含义:

  • 白色:尚未被GC访问到的对象(初始状态所有对象都是白色)
  • 灰色:对象本身已被访问,但其引用的子对象还没有被检查
  • 黑色:对象本身和其所有子对象都已被访问完成
阅读全文
×

(为防止恶意爬虫)
扫码或搜索:HelloCoder
发送:290992
即可永久解锁本站全部文章

解锁
#JVM#面试题二
上次更新: 2025-12-04 10:36:01
最近更新
01
prometheus指标脱坑
12-04
02
什么是IDEA
12-04
03
Gradle项目导入
12-04
更多文章>
Theme by Vdoing | Copyright © 2020-2025 码农阿雨
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式