专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 职业指南 比较经典的一些jvm调优策略面试题

比较经典的一些jvm调优策略面试题

更新时间:2023-01-30 15:05:54 来源:动力节点 浏览963次

JVM性能调优是一个很大的话题,很多中小企业的业务规模受限,没有迫切的性能调优需求,但是如果不知道JVM相关的理论知识,写出来的代码或者配置的JVM参数不合理时,就会出现很严重的性能问题,到时候开发就会像热锅上的蚂蚁,等待各方的炙烤。今天小编总结了一些相关的面试题,一是希望能够应对性能调优岗位相关的面试;二是希望总结一下具体的实战步骤,并努力吸收书中的实践案例,让自己的经验更丰富一些。

jvm调优策略面试题

JVM性能调优

内存溢出错误

学习目的:

通过异常信息及时定位到发生内存溢出的运行时数据区域

了解什么样的代码会导致内存溢出,防止写出这样的代码

出现异常后该如何处理,也就是学习事中的处理手段

内存溢出和内存泄露的区别

内存泄露:不该留存在进程中的内存数据,虽然很小,但是在经过多次长期的积累后,会导致内存溢出

内存溢出:程序申请内存时,内存不足的现象

堆溢出错误和预判堆溢出的错误

如何复现出堆溢出错误?

JVM参数部分:最大堆和最小堆设置相同并且设置的比较小,比如只有10M,这样就不会自动扩展堆

代码部分:在一个方法中不断地往集合中加入元素

代码实践

package org.example;

import java.util.ArrayList;
import java.util.List;

/**
 * -Xmx10M -Xms10M -XX:+HeapDumpOnOutOfMemoryError
 */
public class App {
    static class OOMObject {
        int a = 1;
        long b = 2;
        float c = 2.1f;
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while (true) {
            list.add(new OOMObject());
        }
    }
}

正确的出现了我们想要的结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid24476.hprof ...
Heap dump file created [13268403 bytes in 0.077 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at org.example.App.main(App.java:22)

Process finished with exit code 1

如果把参数调大,调整20M,那么会报另外的error

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid8796.hprof ...
Heap dump file created [27391983 bytes in 0.141 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at org.example.App.main(App.java:19)

Process finished with exit code 1

这个错误的原因是,JVMGC时间占据了整个运行时间的98%,但是回收只得到了2%可用的内存,至少出现5次,就会报这个异常。

这个异常是Jdk1.6定义的策略, 通过统计GC时间来预测是否要OOM了,提前抛出异常,防止OOM发生。

案例心得:

  • 堆内存溢出的识别:java.lang.OutOfMemoryError: Java heap space 或者 java.lang.OutOfMemoryError: GC overhead limit exceeded
  • 死循环中不断创建对象这种代码应该规避
  • 提前设置好自动转储的参数,出现异常能够恢复现场查看问题
  • 事后排查思路:先用JvisualVM这样的软件查看具体对象,核查是内存溢出还是内存泄漏,如果确定没有泄露,需要排查堆的参数设置是否合理,从代码上分析对象存活时长比较长是否必要,是否可以优化等等。

虚拟机栈和本地方法栈溢出错误

一般我们会遇到两种栈相关的错误:

单个线程中,不断的调用方法入栈,当栈深度超过虚拟机所允许的最大深度时,抛出StackOverflowError

不断地创建线程,创建线程就需要创建栈,当无法申请到足够的内存,就会报 unable to create new native thread错误

如何复现?

JVM参数:-Xss128k,每个线程的栈内存大小

代码部分:没有出口的递归调用

代码实践

/**
 * -Xss128k
 */
public class App {
    static int length = 0;

    private static void reverse() {
        length++;
        reverse();
    }

    public static void main(String[] args) {
        try {
            reverse();
        } catch (Throwable e) {
            System.out.println("length:" + length);
            throw e;
        }
    }
}

 结果验证:

length:1096
Exception in thread "main" java.lang.StackOverflowError
	at org.example.App.reverse(App.java:10)
	at org.example.App.reverse(App.java:11)
	at org.example.App.reverse(App.java:11)
	at org.example.App.reverse(App.java:11)
    太多了,这里只截取部分

关于unable to create new native thread这个异常,这里就不尝试了,因为可能会导致操作系统假死等问题。

案例心得:

  • 栈错误的识别:StackOverflowError 或者 java.lang.OutOfMemoryError: unable to create new native thread
  • 没有出口的递归调用要避免;默认的JVM栈大小的参数针对一般的方法调用深度是足够的
  • 如果必须要创建大量的常驻线程,并且是32位的虚拟机,要测试协调好 栈内存和其他内存的大小,防止出现溢出错误
  • 事后排查思路:先确定是哪种错误,然后检查递归调用或者检查线程数

以上就是“比较经典的一些jvm调优策略面试题”,你能回答上来吗?如果想要了解更多的Java面试题相关内容,可以关注动力节点Java官网。 

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>