性能测试常见的内存溢出问题: JVM 内存溢出如何调优?

本贴最后更新于 180 天前,其中的信息可能已经时移世易

前言

针对java项目做性能测试的时候,很多同学都见过一个报错,就是OOM【Out Of MemoryError】;那出现这种报错就是项目发生了内存溢出的问题,这是比较严重的性能问题。所以,作为一个性能测试工程师,我们要能够分析JVM内存的问题以及理解其中的原理,才能更好的给JVM内存出现的性能瓶颈问题进行调优。

JVM概念

要学习JVM内存问题分析和调优之前,我们先来了解一下什么是JVM?

JVM【java virtual machine】: java虚拟机,是Java程序运行所需要的一台虚拟机器。

在操作系统上运行一个java程序的过程中,也就是通过“java -jar ” 启动一个java进程的同时就会启动一个java虚拟机。java虚拟机是在操作系统之上的程序,JVM直接和操作系统进行交互,不跟硬件直接交互。

但是java虚拟机可以管理自己的进程和线程,有自己独立的内存,管理自己的内存,这个叫做JVM内存。

图片.png

JVM的优点

JVM内存模型

现在的java程序都是基于1.8版本,因为java1.8是目前稳定主流的版本,企业基本都兼容1.8及其以上的版本,所以我们学习1.8java版本的内存模型就可以了。

注意:不同版本之间JVM内存存在一定差异,比如只有1.8的版本及之后才有元空间的概念,之前的jvm没有元空间。

jvm运行时有5块数据区,分别如下:

图片.png

五个部分分别来详细介绍一下:

1、程序计数器:线程私有,用于存储指向下一条指令的地址,是一块很小的空间,一般不会有内存问题,也不会进行垃圾回收。所以做性能测试的时候我们不太需要关注。

2、虚拟机栈:线程私有,随着线程创建而创建,随着线程消失而销毁。

3、本地方法栈:与虚拟机栈类似,是线程私有的 ,发生性能问题的概率很低,所以不需要太多关注。

4、方法区【元空间】:是线程共享的,共享的意思就是随着程序的启动而启动,除非进程关掉才会消失,不会因为线程而消失。比如一个方法里比如有10个线程,共享方法区里面的类、常量、静态变量等信息,不会每个线程启动单独开辟一个空间给它,而是大家共享这个方法区。

**5、堆:**这是线程共享的 ,jvm内存最大最重要的区域,性能问题出现比较多的地方,一定要重点掌握。

堆里划分为:新生代、老年代 ,注意:java1.8版本里只有这两个,没有永久代了

图片.png

当新生代和老年代都占满了,GC也释放不出来更多内存了,如果此时还在产生一些新的对象,那么就会发生内存溢出【OOM】的错误,如下图所示:

图片.png

JVM的参数设置

了解了JVM的组成部分,那么在启动项目的时候为了调整性能我们就可以针对JVM内存的大小的设置和调整来优化项目的性能。常见的参数有:

图片.png

如何设置这些参数呢?我们来结合项目实际案例给大家讲解这些参数的设置:

1、启动某JAVA项目进程,ps -ef 查看java进程id:

图片.png

2、使用jmap -heap 1727 命令查看这个java进程的 jvm的内存设置,这些是在代码里写好的默认初始值:

图片.png

3、还可以看到堆内存的使用情况:

图片.png

4、如果要修改和调整这些大小,就可以去修改项目的配置文件。

比如如果你们的是基于tomcat的,那么可以修改catalina.bat 或者 catalina.sh 配置文件来调整这些参数的大小,如下图,在配置文件里加一行设置参数大小,并保存文件:

图片.png

5、配置完成后,重新shutdown tomcat的服务 再次启动这个服务:

图片.png

常见JVM内存的面试题

1、JVM里哪些内存会被回收【GC】?
2、JVM内存会在什么时候被回收?
回帖
请输入回帖内容 ...