Java面试常见问题:JVM内存异常及内存参数设置

createh52周前 (12-17)技术教程9

前文《Java面试必考问题:JVM内存区域如何划分? 》介绍了Java虚拟机的内存区域划分。内存异常问题是程序开发过程中经常遇到的问题,也是面试中常问到的,本文重点介绍一下JVM的内存异常以及相关的内存参数如何设置。

JVM内存异常

遇到的内存不足方面的异常主要是以下三种:

  • java.lang.OutOfMemoryError: Java heap space,表示堆内存不足。
  • java.lang.OutOfMemoryError: PermGen space,表示永久代空间不足。
  • java.lang.StackOverflowError,表示栈溢出。

堆区(Heap)是Java垃圾回收的主要处理区域。如果程序创建很多类实例,而堆内存设置过小,即使有垃圾回收机制,也可能会出现堆内存不足的异常。

永久代(PermGen:Permanent Generation)是HotSpot虚拟机对Java虚拟机规范中定义的方法区的具体实现,这部分一般不会进行垃圾回收,但是在FULL GC时还是会进行回收的。

栈溢出的出现往往意味着程序逻辑存在问题,需要检查代码中是否存在无限递归,递归过多,调用过深等情况。

在Java8中,不再使用永久代, 而是引入了元空间(Metaspace)作为方法区的实现。元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。

永久代空间不足的异常,也被元空间不足的异常取代:

  • java.lang.OutOfMemoryError: Metaspace,表示元空间已被用满。

元空间使用量与JVM加载到内存中的 class 大小和数量有关。元空间OOM错误的主要原因就是加载到内存中的 class 数量太多或者体积太大。

堆内存的设置

遇到内存问题,最直接的办法是调整JVM的内存设置。

堆内存的主要参数包括:

  • -Xms1500m:初始堆大小,设置为1.5GB。
  • -Xmx2000m:最大堆大小,设置为2GB。

通常来说,堆内存设置的参数主要是这两个参数。当出现堆内存OOM错误的时候,可能是程序运行中产生了超出预期的数据量,可以通过增加最大堆大小来尝试解决。如果仍然不行,需要考虑使用多个虚拟机进行负载均衡。

另外也需关注程序是否存在内存泄露(Memory leak),如果存在,那么随着运行时间的推移, 泄漏的对象会占用越来越多的内存,直到耗光堆中的所有内存。增加再大的堆内存也无济于事。

通常堆内存只需要设置上面这两个参数就行了。除了这两个参数以外,还有其他一些堆内存相关的参数。

  • -XX:NewSize=n:设置年轻代的初始大小
  • -XX:MaxNewSize=n:设置年轻代的最大大小
  • -Xmn: 表示固定设置年轻代的大小,也就是上面两个值变成同一个值了。

增大年轻代的大小,将会减小年老代的大小。此外还可以设置年轻代(包括Eden和两个Survivor区)与年老代的内存比例。

  • -XX:NewRatio=4 表示年轻代与年老代所占比例为1:4,年轻代占整个堆内存的1/5.

其他JVM内存设置

永久代设置(Java8以前)

永久代(PermGen) 使用量和JVM加载到内存中的 class 大小及数量有关。出现OOM错误的原因是加载到内存中的 class 数量太多或体积太大。以下两个参数与永久代设置有关:

  • -XX:PermSize=512m:设置永久代初始大小为512MB。
  • -XX:MaxPermSize=512m:设置永久代最大大小为512MB。

元空间设置(Java8及以后)

JDK1.8以后出现了元空间,作用和永久代类似。元空间的大小用以下参数设置:

  • -XX:MetaspaceSize=512m
  • -XX:MaxMetaspaceSize=512m

上面的意思就是将元空间大小的初始值和最大值设置为 512MB。只要不超过,就不会出现OOM。

栈区设置

  • -Xss:设置栈的大小,也就是每个线程可使用的内存大小。一般默认为512K。

栈的设置参数一般很少用到。

总结

堆内存不是设置得越大越好。堆内存太大,虽然不会出现OOM,但是可能会增加垃圾回收暂停的时间,影响程序的吞吐量和延迟。对于JVM内存设置,我们还是要结合自己应用的特点,选择合适的参数。

我会持续更新关于物联网、云原生以及数字科技方面的文章,用简单的语言描述复杂的技术,也会偶尔发表一下对IT产业的看法,欢迎大家关注、转发和评论,谢谢。

相关文章

java -jar 启动参数 java -jar 启动参数 内存

/usr/local/java/jdk1.8.0_131/bin/java -jar -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=...

java命令行参数 java命令行参数表示形式

命令行参数就是main方法里面的参数String[] args他就是一个数组,args只是数据类型的一个名称,就是一个数组的变量,名称无所谓,类型没变就行了。这个就是程序的入口点。如图7.4所示:图7...

腾讯大佬详细讲解Java 启动exe程序,传递参数和获取参数

这篇文章主要介绍了java 启动exe程序,传递参数和获取参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧1、java中启动exe程序 ,并添加传参String[] cmd =...

JVM诊断之查看运行参数 jvm运行参数说明

问题描述为了分析和定位一个Java线上系统问题,我们需要查看JVM启动时的一些参数设置,例如:垃圾回收算法、堆大小等等。这些参数可能在启动脚本中明确指明,也可能采用默认值。在系统运行过程中其他人也许动...

WebService的发布与调用 webservices调用

WebService 简介首先先说一下,什么是webService,webService也是一种CS结构的WEB服务,C呢就是Client(客户端),S呢就是Server(服务端),webServic...

Java方法参数传递的机制 java方法参数可以传空吗

目前两种比较流行的方法参数传递模式主要是值传递和引用传递。不同的编程语言对于这两种机制可能有不同的处理方式。对Java来说,一切都是严格按值传递的。接下来,我们来一起探讨下 Java 如何为各种类型传...