JVM异常及解决办法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42220174/article/details/102641981


在Java虚拟机规范中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能。下面是一些常见的异常及解决方法:

Java堆溢出

       Java堆用于存储对象实例,只要不断的创建对象,并保证GC Root到对象之间有可达的路径即可避免垃圾回收机制清除那些对象,那么当对象数量达到最大堆的容量限制后就会产生内存超出异常。

/**
 * 测试堆内存溢出
 * 参数为:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * @author 
 *
 */
public class HeapOOM {

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

}

运行结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid2216.hprof ...
Heap dump file created [15858972 bytes in 0.091 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 ErrorAndException.HeapOOM.main(HeapOOM.java:18)

分析:Java堆内存溢出时,异常堆栈信息java.lang.OutOfMemoryError后会进一步提示Java heap space
解决办法:
       先通过内存映像分析工具(如Eclipse Memory Analyzer)对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是先分清楚是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。
       如果是内存泄漏,可进异一步通过工具查看泄漏对象到GC Roots的引用链。就可以比较准确的定位泄漏代码的位置。
       如果不存在泄漏,也就是说,内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xms与-Xmx),与物理机内存对比看是否还能增大;代码上,看是否存在一些对象生命周期过长的情况,尝试减少程序运行期间的内存消耗。

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

栈容量只由-Xss参数设定,虚拟机栈和本地方法栈存在两种异常:

  • StackOverflowError异常:当线程请求的栈深度大于虚拟机所允许的最大深度时(无限递归),会抛出StackOverflowError异常。
  • OutOfMemoryError异常:当虚拟机在扩展栈时无法申请到足够的内存空间时,会抛出OutOfMemoryError异常。
public class StackOverflowException01 {

	int stackLength = 1;

	void addPlusPlus() {
	     this.stackLength++;
	     this.addPlusPlus();
	}

	public static void main(String[] args) throws  Throwable{
	  	StackOverflowException01 oom = new StackOverflowException01();
	  	try {
	   		oom.addPlusPlus();
	  	}catch(Throwable e) {
	   		System.out.println("stack length :"+ oom.stackLength);
	   		throw e;
	  	}
	}
		
}

运行结果:

stack length :99098
Exception in thread "main" java.lang.StackOverflowError
 	at ErrorAndException.StackOverflowException01.addPlusPlus(StackOverflowException01.java:14)
	at ErrorAndException.StackOverflowException01.addPlusPlus(StackOverflowException01.java:14)
 	at ErrorAndException.StackOverflowException01.addPlusPlus(StackOverflowException01.java:14)
 	......

分析:在单个线程下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,虚拟机抛出的都是StackOverflowError异常。
解决办法:Java虚拟机栈大小 = 每个进程的内存大小 - JVM堆大小 - JVM方法区大小 - 程序计数器大小

  • 减少线程数
  • 更换64位虚拟机
  • 减少最大堆和减少栈容量来换取更多的内存

方法区和运行时常量池溢出

运行时常量池是方法区的一部分。运行时常量区溢出时,在OutOfMemoryError后面的提示信息是PerGen space,说明运行时常量池属于方法区的一部分。

猜你喜欢

转载自blog.csdn.net/qq_42220174/article/details/102641981