java.lang.StackOverflowError 
栈溢出错误,这个错误很容易模拟,且看下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public  static  void  main (String[] args)   {  new  StackOverflowTest().test(); } private  static  int  high = 0 ;private  void  test ()   {  try  {     ++high;     test();   } finally  {     System.out.println("栈的深度为: "  + high);   } } --- JVM ARGS: -server -Xmn2m -Xss1m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-UseTLAB 
 
释
 
我们都知道方法的调用是通过入栈和计算出栈来实现的,所以我们在方法递归调用一定次数时,必然会发生栈溢出,栈溢出后,程序自动停止,是一类不可捕获和恢复的Error类型的错误,所以我们在使用递归算法时,应当注意递归的深度,防止出现栈溢出错误导致服务错误
  java.lang.OutOfMemoryError:java heap space 
JVM堆空间不足引起的内存溢出错误,这类错误比较常见,此处就不做太多的解释,出现这类错误,你就去看GC日志,看看新生代、老年代、永久代/Metaspace的使用情况,如果是想查看GC的情况,使用如下JVM指令:
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:./gclog.log,gc的所有信息都会输出到gclog.log文件中
gclog.log
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 *JVM信息* Java HotSpot (TM)  64-Bit Server VM  (25.161 -b12)  for  bsd-amd64 JRE  (1.8 .0 _161-b12) , built on Dec 19 2017 16:22:20 by "java_re" with gcc 4.2.1 (Based on Apple Inc. build 5658 )  (LLVM build 2336.11 .00 )  Memory: 4k page, physical 16777216k (2991720 k free)  /proc/meminfo: *JVM ARGS* CommandLine flags: -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:InitialHeapSize =268435456  -XX:MaxHeapSize=4294967296  -XX:MaxNewSize=2097152  -XX:NewSize=2097152  -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:ThreadStackSize=1024  -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC -XX:-UseTLAB *GC日志信息* 0.125 : [GC (Allocation Failure) [PSYoungGen: 1023 K->512 K(1536 K)] 1023 K->536 K(261632 K), 0.0010704  secs] [Times: user=0.01  sys=0.00 , real=0.00  secs] 0.157 : [GC (Allocation Failure) [PSYoungGen: 1535 K->493 K(1536 K)] 1559 K->847 K(261632 K), 0.0010655  secs] [Times: user=0.01  sys=0.00 , real=0.00  secs] ... 0.360 : [GC (Allocation Failure) [PSYoungGen: 1247 K->256 K(1536 K)] 2614 K->1727 K(261632 K), 0.0008285  secs] [Times: user=0.00  sys=0.00 , real=0.00  secs] Heap  *年轻代*  PSYoungGen      total 1536 K, used 396 K [0x00000007bfe00000 , 0x00000007c0000000 , 0x00000007c0000000 )   eden space 1024 K, 13 % used [0x00000007bfe00000 ,0x00000007bfe23268 ,0x00000007bff00000 )   from space 512 K, 50 % used [0x00000007bff00000 ,0x00000007bff40000 ,0x00000007bff80000 )   to   space 512 K, 0 % used [0x00000007bff80000 ,0x00000007bff80000 ,0x00000007c0000000 )  *老年代*  ParOldGen       total 260096 K, used 1471 K [0x00000006c0000000 , 0x00000006cfe00000 , 0x00000007bfe00000 )   object space 260096 K, 0 % used [0x00000006c0000000 ,0x00000006c016fc00 ,0x00000006cfe00000 )  *Metaspace空间,jdk8+*  Metaspace       used 3402 K, capacity 4500 K, committed 4864 K, reserved 1056768 K   class  space     used  368K , capacity  388K , committed  512K , reserved  1048576K  
 
代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 public  static  void  main (String[] args)   {  new  StackOverflowTest().heapSpace(); } private  void  heapSpace ()   {  List<String> list = new  ArrayList<>();   while  (true ) {     list.add(new  String("abc" ));   } } ---   JVM ARGS: -server -Xmn2m -Xss1m -Xms1m -Xmx1m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:-UseTLAB 
 
  java.lang.OutOfMemoryError:GC overhead limit exceeded 
超出了GC开销限制引起的内存溢出,这个错误不是特别常见,Sun 官方对此的定义:超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常,可以使用参数-XX:-UseGCOverheadLimit 禁用这个检查,但是这个参数解决不了内存问题,只是把错误的信息延后,替换成 java.lang.OutOfMemoryError: Java heap space
Metaspace内存溢出,Metaspace是jdk8+特有的东西,用来代替之前的PermGen,主要存储class名称、字段、方法、字节码、常量池、JIT优化代码等等,我们可以使用-XX:MetaspaceSize和-XX:MaxMetaspaceSize来指定其大小,一般情况下Metaspace不会发生OOM,Metaspace的使用量与JVM加载的class数量有很大关系:
代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static  ClassPool cp = ClassPool.getDefault();public  static  void  main (String[] args)  throws  CannotCompileException  {  int  i = 0 ;   try  {     for  (;; i++) {       Class cz = cp.makeClass("com.example.demo.bean.DemoBean"  + i).toClass();     }   } catch  (Exception e) {   } finally  {     System.out.println(i);   } } ---   JVM ARGS: -XX:MetaspaceSize=10 m -XX:MaxMetaspaceSize=10 m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
 
输出
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0.598 : [GC (Metadata GC Threshold) [PSYoungGen: 39345 K->10741 K(76288 K)] 39345 K->15811 K(251392 K), 0.0111319  secs] [Times: user=0.05  sys=0.01 , real=0.01  secs] 0.609 : [Full GC  (Metadata GC Threshold)  [PSYoungGen: 10741K->0K (76288 K) ] [ParOldGen: 5069K->15550K (139776 K) ] 15811K->15550K (216064 K) , [Metaspace: 9735K->9735K (1056768 K) ], 0.0504762 secs] [Times: user =0.29  sys=0.01 , real=0.05  secs] ... 0.754 : [GC (Last ditch collection) [PSYoungGen: 0 K->0 K(82944 K)] 15477 K->15477 K(472064 K), 0.0008113  secs] [Times: user=0.00  sys=0.00 , real=0.01  secs] 0.755 : [Full GC  (Last ditch collection)  [PSYoungGen: 0K->0K (82944 K) ] [ParOldGen: 15477K->15477K (607232 K) ] 15477K->15477K (690176 K) , [Metaspace: 9733K->9733K (1056768 K) ], 0.0204189 secs] [Times: user =0.08  sys=0.00 , real=0.02  secs] 5341 Exception in thread "main"  java.lang.OutOfMemoryError: Metaspace 	at javassist.ClassPool.toClass(ClassPool.java:1170 ) 	at javassist.ClassPool.toClass(ClassPool.java:1113 ) 	at javassist.ClassPool.toClass(ClassPool.java:1071 ) 	at javassist.CtClass.toClass(CtClass.java:1275 ) 	at com.example.demo.jvm.MetaspceOOMTest.main(MetaspceOOMTest.java:13 ) Heap  PSYoungGen      total 82944 K, used 2390 K [0x000000076ab00000 , 0x0000000772c00000 , 0x00000007c0000000 )   eden space 82432 K, 2 % used [0x000000076ab00000 ,0x000000076ad55ab0 ,0x000000076fb80000 )   from space 512 K, 0 % used [0x0000000772b80000 ,0x0000000772b80000 ,0x0000000772c00000 )   to   space 10752 K, 0 % used [0x0000000771700000 ,0x0000000771700000 ,0x0000000772180000 )  ParOldGen       total 607232 K, used 15477 K [0x00000006c0000000 , 0x00000006e5100000 , 0x000000076ab00000 )   object space 607232 K, 2 % used [0x00000006c0000000 ,0x00000006c0f1d4c8 ,0x00000006e5100000 )  Metaspace       used 9770 K, capacity 10084 K, committed 10240 K, reserved 1056768 K   class  space     used  3165K , capacity  3214K , committed  3328K , reserved  1048576K  
 
我们将Metaspace的初始大小和最大值都设置为10m,最终i的值大概会在5340左右的时候报OOM,从FGC的日志可以看出,Metaspace在整个GC阶段都未进行任务的内存回收,直至被全部用完,具体的关于Metaspace的介绍可以看下PerfMa社区的这篇文章:https://club.perfma.com/article/210111 
  java.lang.OutOfMemoryError:Direct buffer memory 
ByteBuffer. allocateDirect (int capability)是分配操作系统的本地内存,不在GC管辖范围之内,由于不需要内存拷贝所以速度相对较快,但如果不断分配本地内存,堆内存就会很少使用,那么JVM就不需要进行GC,那创建的DirectByteBuffer对象就不会被回收,就会出现堆内存充足但本地内存不足的情况,继续尝试分配本地内存就会出现OOM。
代码
 
1 2 3 4 5 6 7 public  static  void  main (String[] args)   {  System.out.println("当前direct大小: "  + (VM.maxDirectMemory() / 1024  / 1024 ) + " MB" );   ByteBuffer bb = ByteBuffer.allocateDirect(Math.toIntExact(VM.maxDirectMemory() + 10 )); } ---   JVM ARGS: -XX:MaxDirectMemorySize=10 m 
 
这里我们需要通过JVM参数-XX:MaxDirectMemorySize=10将JVM本地最大使用内存设置为10MB,不然如果你本地剩余内存很大,那么就很难模拟出此错误
输出
 
1 2 3 4 5 6 当前direct大小: 10  MB Exception in thread "main"  java.lang.OutOfMemoryError: Direct buffer memory 	at java.nio.Bits.reserveMemory(Bits.java:694 ) 	at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123 ) 	at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311 ) 	at com.example.demo.jvm.DirectBufferOOMTest.main(DirectBufferOOMTest.java:11 ) 
 
  java.lang.OutOfMemoryError:unable create new native thread 
线程创建的太多,导致无法继续创建线程,出现这个问题就要去使用jstack导出线程栈查看具体情况
代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 public  static  void  main (String[] args)   {  while  (true ) {     new  Thread(new  Runnable() {       @Override        public  void  run ()   {         try  {           Thread.sleep(100000 );         } catch  (InterruptedException e) {         }       }     }).start();   } } 
 
这一段代码必然会出现该ERROR,不论你的机器有多牛掰,你会发现出现了OOM之后,进程并未终止,这个时候你可以用jps命令查看进程号,然后使用jstack pid查看线程栈,会发现有非常多的线程处于TIMED_WAITING (sleeping)状态:
1 2 3 4 5 "Thread-256" #267 prio=5 os_prio=31 tid=0x00007fccdd8cc000 nid=0x27d03 waiting on condition [0x0000700019b85000]    java.lang.Thread.State: TIMED_WAITING (sleeping) 	at java.lang.Thread.sleep(Native Method) 	at com.example.demo.jvm.NativeThreadOOMTest$1 .run(NativeThreadOOMTest.java:11 ) 	at java.lang.Thread.run(Thread.java:748 )