天天看点

重点:JVM 常见面试题进阶JVM 常见面试题进阶实战

java架构师面试题

比较全的面试题目

JVM 常见面试题进阶

提示:

再把“Java核心知识点整理”的jvm部分加上,也看看,整合到一起。

1.1 Java 语言怎么实现跨平台的?

我们编写的 Java 源码,编译后会生成一种 .class 文件,称为字节码文件。字节码不能直接运行,必须通过 JVM 翻译成机器码才能运行。

JVM 是一个”桥梁“,是一个”中间件“,是实现跨平台的关键。Java 代码首先被编译成字节码文件,再由 JVM 将字节码文件翻译成机器语言,从而达到运行 Java 程序的目的。

1.2 JVM 数据运行区,哪些会造成 OOM 的情况?

除了数据运行区,其他区域均有可能造成 OOM 的情况。

堆溢出:java.lang.OutOfMemoryError: Java heap space

栈溢出:java.lang.StackOverflowError

永久代溢出:java.lang.OutOfMemoryError:PermGen space

1.3 详细介绍一下对象在分代内存区域的分配过程?

  1. JVM 会试图为相关 Java 对象在 Eden 中初始化一块内存区域。
  2. 当 Eden 空间足够时,内存申请结束;否则到下一步。
  3. JVM 试图释放在 Eden 中所有不活跃的对象(这属于 1 或更高级的垃圾回收)。释放后若 Eden 空间仍然不足以放入新对象,则试图将部分 Eden 中活跃对象放入 Survivor 区。
  4. Survivor 区被用来作为 Eden 及 Old 的中间交换区域,当 Old 区空间足够时,Survivor 区的对象会被移到 Old 区,否则会被保留在 Survivor 区。
  5. 当 Old 区空间不够时,JVM 会在 Old 区进行完全的垃圾收集。
  6. 完全垃圾收集后,若 Survivor 及 Old 区仍然无法存放从 Eden 复制过来的部分对象,导致 JVM 无法在 Eden 区为新对象创建内存区域,则出现 “ out of memory ” 错误。

1.4 G1 与 CMS 两个垃圾收集器的对比

细节方面不同

  • G1 在压缩空间方面有优势。
  • G1 通过将内存空间分成区域(Region)的方式避免内存碎片问题。
  • Eden, Survivor, Old 区不再固定、在内存使用效率上来说更灵活。
  • G1 可以通过设置预期停顿时间(Pause Time)来控制垃圾收集时间避免应用雪崩现象。
  • G1 在回收内存后会马上同时做合并空闲内存的工作、而 CMS 默认是在 STW(stop the world)的时候做。
  • G1 会在 新生代和年老代 中使用、而 CMS 只能在 O 区使用。
  • 整体内容不同

吞吐量优先:G1

响应优先:CMS

CMS 的缺点是对 cpu 的要求比较高。G1 是将内存化成了多块,所有对内段的大小有很大的要求。

CMS 是清除,所以会存在很多的内存碎片。G1 是整理,所以碎片空间较小。

1.5 线上常用的 JVM 参数有哪些?

数据区设置

Xms:初始堆大小

Xmx:最大堆大小

Xss:Java 每个线程的Stack大小

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:设置持久代大小。

JvM 参数调优:
 一 xms < size >表示jvM 初始化堆的大小, : Xmx < size >表示 JvM 堆的最大值。这两个值的大小一般根据需要进行设置。当应用程序需要的内存超出堆的最大值时虚拟机就会提示内存溢出,并且导致应用服务崩溃。因此一般建议堆的最大值设置为可用内存的最大值的 80 %。
 在 catalina . bat 中,设置 JAvA _ OPTS = ’一 Xms256m - Xmxs 12m ' ,表示初始化内存为 256MB ,可以使用的最大内存为 51 ZMB 。
           

收集器设置

XX:+UseSerialGC:设置串行收集器

XX:+UseParallelGC::设置并行收集器

XX:+UseParalledlOldGC:设置并行年老代收集器

XX:+UseConcMarkSweepGC:设置并发收集器

GC日志打印设置

XX:+PrintGC:打印 GC 的简要信息

XX:+PrintGCDetails:打印 GC 详细信息

XX:+PrintGCTimeStamps:输出 GC 的时间戳

1.6 对象什么时候进入老年代?

对象优先在 Eden 区分配内存

当对象首次创建时, 会放在新生代的 eden 区, 若没有 GC 的介入,会一直在 eden 区,GC 后,是可能进入 survivor 区或者年老代

大对象直接进入老年代

所谓的大对象是指需要大量连续内存空间的 Java 对象,最典型的大对象就是那种很长的字符串以及数组,大对象对虚拟机的内存分配就是坏消息,尤其是一些朝生夕灭的短命大对象,写程序时应避免。

长期存活的对象进入老年代

虚拟机给每个对象定义了一个对象年龄(Age)计数器,对象在 Survivor 区中每熬过一次 Minor GC,年龄就增加 1,当他的年龄增加到一定程度(默认是 15 岁), 就将会被晋升到老年代中。

1.7 什么是内存溢出, 内存泄露? 他们的区别是什么?

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory;

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。

内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。

什么情况下会出现栈溢出

  • 方法创建了一个很大的对象,如 List,Array。
  • 是否产生了循环调用、死循环。
  • 是否引用了较大的全局变量。

1.8 引起类加载操作的行为有哪些?

  • 遇到 new、getstatic、putstatic 或 invokestatic 这四条字节码指令。
  • 反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
  • 子类初始化的时候,如果其父类还没初始化,则需先触发其父类的初始化。
  • 虚拟机执行主类的时候(有 main( string[] args))。
  • JDK1.7 动态语言支持。

1.9 介绍一下 JVM 提供的常用工具

jps:用来显示本地的 Java 进程,可以查看本地运行着几个 Java 程序,并显示他们的进程号。 命令格式:jps

jinfo:运行环境参数:Java System 属性和 JVM 命令行参数,Java class path 等信息。 命令格式:jinfo 进程 pid

jstat:监视虚拟机各种运行状态信息的命令行工具。 命令格式:jstat -gc 123 250 20

jstack:可以观察到 JVM 中当前所有线程的运行情况和线程当前状态。 命令格式:jstack 进程 pid

jmap:观察运行中的 JVM 物理内存的占用情况(如:产生哪些对象,及其数量)。 命令格式:jmap [option] pid

1.10 Full GC 、 Major GC 、Minor GC 之间区别?

Minor GC: 从新生代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。

Major GC: 清理 Tenured 区,用于回收老年代,出现 Major GC 通常会出现至少一次 Minor GC。

Full GC: Full GC 是针对整个新生代、老年代、元空间(metaspace,java8 以上版本取代 perm gen)的全局范围的 GC。

1.11 什么时候触发 Full GC ?

  • 调用 System.gc 时,系统建议执行 Full GC,但是不必然执行。
  • 老年代空间不足。
  • 方法区空间不足。
  • 通过 Minor GC 后进入老年代的平均大小大于老年代的可用内存。
  • 由 Eden 区、survivor space1(From Space)区向 survivor space2(To Space)区复制时,对象大小大于 To Space 可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。

1.12 什么情况下会出现栈溢出

  • 方法创建了一个很大的对象,如 List,Array。
  • 是否产生了循环调用、死循环。
  • 是否引用了较大的全局变量。

1.13 说一下强引用、软引用、弱引用、虚引用以及他们之间和 gc 的关系

强引用:new 出的对象之类的引用,只要强引用还在,永远不会回收。

软引用:当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。

弱引用:只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。

虚引用:主要作用是跟踪对象被垃圾回收的状态。

1.14 Eden 和 Survivor 的比例分配是什么情况?为什么?

默认比例 8:1。 大部分对象都是朝生夕死。 复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

实战

JAVA 线上故障排查完整套路!

2.1 CPU 资源占用过高

  1. top 查看当前 CPU 情况,找到占用 CPU 过高的进程 PID=123。
  2. top -H -p123 **可以找出两个 CPU 占用较高的线程,**记录下来 PID=2345, 3456 转换为十六进制。
  3. jstack -l 123 > temp.txt 打印出当前进程的线程栈。

    可以观察到 JVM 中当前所有线程的运行情况和线程当前状态。

  4. 查找到对应于第二步的两个线程运行栈,分析代码。

2.2 OOM 异常排查

1.使用 top 指令查询服务器系统状态。

\2. ps -aux|grep java 找出当前 Java 进程的 PID。

\3. jstat -gcutil pid interval 查看当前 GC 的状态。

\4. jmap -histo:live pid 可用统计存活对象的分布情况,从高到低查看占据内存最多的对象。

\5. jmap -dump:format=b,file= 文件名 [pid] 利用 Jmap dump。

\6. 使用性能分析工具对上一步 dump 出来的文件进行分析,工具有 MAT 等。

JVM常见面试题基础

继续阅读