JVM-ERROR
# JVM-ERROR(SOFE,OOM,UNKNOW)
- 架构

- 常见Error
- java.lang.StackOverFlowError
- java.lang.OutOfMemoryEorror:Java heap space
- java.lang.OutOfMemoryEorror:GC overhead limit exceeded
- java.lang.OutOfMemoryEorror:Direct buffer memory
- java.lang.OutOfMemoryEorror:unable to create new native thread
- java.lang.OutOfMemoryEorror:Metaspace
# SOFE(StackOverFlowError)
- Demo
public class StackOverFlowErrorDemo {
public static void main(String[] args) {
stackOverFlowErrorDemo();
}
public static void stackOverFlowErrorDemo(){
stackOverFlowErrorDemo();
}
}
//Exception in thread "main" java.lang.StackOverflowError
// at com.jjc.mypratice.javase.jvm.error.stackoverflowerror.StackOverFlowErrorDemo.stackOverFlowErrorDemo(StackOverFlowErrorDemo.java:15)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# OOM(OutOfMemoryError)
Java heap space
- Demo
public class JavaHeapSpaceDemo { public static void main(String[] args) { //-Xms10m -Xmx10m //byte[] bytes = new byte[30 * 1024 * 1024]; String str = "demo"; while(true){ str = str + new Random().nextInt(11111111) + new Random().nextInt(22222222); str.intern(); } } } //Exception in thread "main" java.lang.OutOfMemoryError: Java heap space //at com.jjc.mypratice.javase.jvm.error.outofmemeoryerror.javaheapspace.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:14)1
2
3
4
5
6
7
8
9
10
11
12
13GC overhead limit exceeded
- GC回收时间过长时会地出OutofMemroyError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存,连续多GC都只回收了不到2%的极端情况下才会地出。
- 假如不地出 GC overhead Limit 错误会发生什么情况呢? 那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行,这样就形成恶性循环CPU使用率一直是100%,而GC却没有在何成果.
- Demo
public class GCOverheadLimitExceededDemo { //-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=3m public static void main(String[] args) { int i = 0; List<String> list = new ArrayList<>(); try{ while(true){ list.add(String.valueOf(++i).intern()); } }catch(Throwable e){ System.out.println("***************" + i); e.printStackTrace(); throw e; } } } //java.lang.OutOfMemoryError: GC overhead limit exceeded //at java.lang.Integer.toString(Integer.java:401) //at java.lang.String.valueOf(String.java:3099) //at com.jjc.mypratice.javase.jvm.error.outofmemeoryerror.gcoverheadlimitexceeded.GCOverheadLimitExceededDemo.main(GCOverheadLimitExceededDemo.java:20)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Direct buffer memory
- 写NIO程序经常使用ByteBuffer来读取或写入数据,这是一种基于通道(Channel)和缓冲区(buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过Java堆里面的一个DirectByteBuffer对象作为这块内存的引用操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。
- ByteBuffer.allocate(capatility)第一种方式是分配JVM堆内存,属于GC的管辖范围,由于需要拷贝所以速度较慢。
- ByteBuffer.allocateDirect(capatility)第二种方式是分配OS本地内存,即Native,不属于GC管辖范围,由于不需要内存拷贝所以速度较快。
- 如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,本地内存可能已经被使用光了,再次尝试分配本地内存就会出现OutOfMemory,程序直接崩溃。
- Demo
public class DirectBufferMemoryDemo { public static void main(String[] args) { System.out.println("maxDirectMemory:" + sun.misc.VM.maxDirectMemory() / (double)1024 / 1024 + "MB"); try{ TimeUnit.SECONDS.sleep(3); }catch(Exception e){e.printStackTrace();} //-XX:MaxDirectMemorySize=5m ,配置为5m,实际使用为6m,撑爆MaxDirectMemory ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 *1024); } } //Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory1
2
3
4
5
6
7
8
9unable to create native thread
- 高并发请求服务器时,经常出现如下异常:java.lang.OutOfMemoryEorror:unable to create new native thread。
- 准确的讲,native thread和对应的操作系统平台有关。
- 导致原因:
- 1.应用创建了太多线程了,一个应用进程创建多个线程,超过系统承载极限。
- 2.服务器不允许应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024个,应用创建的线程超过这个数量,就会报错。
- 解决办法:
- 1.降低应用程序创建的线程数量,分析应用是否需要创建这么多线程,如果不是,将线程数降至最低。
- 2.有的应用确实需要这么多线程,修改linux系统的默认1024个线程的限制,扩大默认限制。
- linux服务器调优
- linux普通用户上限1024,root无上限。
- vim /etc/security/limits.d/90-nproc.conf
- Demo
public class UnableToCreateNewThreadDemo { public static void main(String[] args) { int i = 0; while(true){ new Thread(() -> { System.out.println(Thread.currentThread().getName()); try{ TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); }catch(Exception e){e.printStackTrace();} },"" + ++i).start(); } } } //Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread1
2
3
4
5
6
7
8
9
10
11
12Metaspace
- Java8之后使用Metaspace替代永久代
- Metaspace是方法区在HotSpot中的实现,它与持久代最大的区别是:Metaspace并不在虚拟机中而是使用本地内存,也即在Java8中,class metadata(the virtual machines internal presentation of Java class),被存储在叫做Metaspace的native memory
- 永久代(Java8之后被元空间Metaspace取代)存放了以下信息
- 虚拟机加载的类信息
- 常量池
- 静态变量
- 即时编译后的代码
- Demo
//-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m public class MetaspaceDemo { static class MetaspaceError{}; public static void main(String[] args) { int i = 0; try{ while(true){ ++i; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MetaspaceError.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o,args); } }); enhancer.create(); } }catch(Throwable e){ System.out.println("执行" + i + "次后Error"); e.printStackTrace(); } } } //org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspace //Caused by: java.lang.OutOfMemoryError: Metaspace1
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
编辑 (opens new window)
上次更新: 2024/05/24, 11:36:46