import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* OutOfMemoryError 是error 不是异常;Object-Throwable-error-VirtualMechineError-OutOfMemoryError
*/
public class OOMDemo {
public static void main(String[] args) {
Object o = new Object();
//方法分别单独调用,各个方法调用前 先配置OOMDemo项目的vm参数(idea-run-edit configurations-application:项目vm)
//stackOverflowError();
//javaHeapSpace();
//GCOverhead();
//directBufferMemory();
//unableCreateNewThread();
metaspaceOOM(args);
}
/**
* StackOverflowError:栈溢出
* 自己调用自己,深度循环调用。
* Exception in thread "main" java.lang.StackOverflowError
*/
private static void stackOverflowError() {
stackOverflowError();
}
/**
* OutOfMemoryError: Java heap space 堆溢出
* <p>
* 设置堆内存小一些,new大对象 -Xms10m -Xmx10m
* Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
*/
private static void javaHeapSpace() {
Byte[] bytes = new Byte[30 * 1024 * 1024];
}
/**
* GC overhead limit exceeded:GC超出极限,GC一直在高速工作。
* <p>
* GC回收时间过长抛出OutOfMemoryError。过长的定义:超过98%时间用来做GC并且收回了不到2%的堆内存,连续多次GC只回收了不到2%的极端情况下才会抛出。
* 加入不抛出,则2%立马会被填满,迫使再次GC,形成恶行循环,CPU一直是100%,而GC没有任何效果。
* jvm参数配置:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
* [Full GC (Ergonomics) java.lang.OutOfMemoryError: GC overhead limit exceeded
* [Full GC (Ergonomics) [PSYoungGen: 1024K->1024K(2048K)] [ParOldGen: 7086K->7067K(7168K)] 8110K->8091K(9216K), [Metaspace: 3707K->3707K(1056768K)],
* <p>
* <p>
* String.intern():如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符添加到常量池中,并返回此String对象的引用。
*/
private static void GCOverhead() {
int i = 0;
List<String> list = new ArrayList<>();
try {
while (true) {
list.add(String.valueOf(i++).intern());
}
} catch (Throwable e) {
System.out.println("**********i=" + i);
e.printStackTrace();
throw e;
}
}
/**
* 直接内存溢出:
* 导致原因:写NIO程序经常使用ByteBuffe来读取和写入数据,这是一种基于通道channel和缓冲区buffer的I/O方式
* 它可以直接使用Native函数库z直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。
* 这样能在一些场景中显著提高性能,因为避免了在java堆和native堆中来回复制数据。
* <p>
* ByteBuffer.allocate(capability)第一种方式是分配jvm堆内存,属于GC管辖,由于需要copy所以速度慢
* ByteBuffer.allocateDirect(capability)第一种方式是分配OS本地内存,不属于GC管辖,不需要内存copy所以很快。
* <p>
* 但由于不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会被回收。
* 出翔堆内存充足,本地内存耗光。再次分配本地没存就会出现OutOfMemoryError,程序崩溃。
* <p>
* DirectMemory:直接内存,指的是物理内存,默认最大时1/4本地内存
* <p>
* jvm堆内存:DirectMemory直接内存(1/4本地内存):本地内存
* <p>
* 配置参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
* <p>
* 故障现象:Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
* Full GC (System.gc()) [PSYoungGen: 501K->0K(2560K)] [ParOldGen: 1350K->1612K(7168K)] 1852K->1612K(9728K),
* [Metaspace: 3425K->3425K(1056768K)] 元空间满了
*/
private static void directBufferMemory() {
System.out.println("配置的MaxDirectMemorySize:" + sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024 + "MB");
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
}
/**
* 高并发请求处理器时,经常出现如下异常:
* native thread异常与对应平台有关。
* <p>
* 导致原因:
* 1 你的应用创建了太多线程,一个应用进程创建太多线程,超过系统极限;
* 2 服务器并不允许你创建这么多线程,linux默认单个进程最多创建1024个,如果超过就报异常;
* <p>
* 解决办法:
* 1 降低应用进程创建的线程数量,改代码
* 2 对于有的应用,需要很多线程则修改服务器设置,扩大linux的默认值。
* 系统调优:
* 1 ulimit -u (查看默认多少个)
* 2 vim /etc/security/limits.d/90-nproc.conf 查看各个用户限制多少个数 root 无上限,可以怎就该用户 或者更改用户的限制数量
* <p>
* <p>
* <p>
* windows未爆出异常但是 Full GC已经几乎失效
* [Full GC (Ergonomics) [PSYoungGen: 1023K->1023K(2048K)] [ParOldGen: 7168K->7166K(7168K)] 8191K->8190K(9216K), [Metaspace: 3971K->3971K(1056768K)]
* <p>
* LINUX: 默认1024
* 1 cd /aleneuse/ (java文件所在文件夹)
* 2 ll (目录)
* 3 javac -d . OOMDemo.java (编译java文件)
* 4 cat OOMDemo.java (运行需要带包名,查看包名)
* 5 java com.founder.rhip.drs.controller.OOMDemo (运行。包名+类名)
* 之后会报错:
* OutOfMemoryError:unable to create new native thread i<1024
*/
private static void unableCreateNewThread() {
for (int i = 0; ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out.println("Thread" + i);
}
}
/**
*
*OutOfMemoryError: Metaspace 元空间溢出异常
*
* jvm参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
*
* 代替永久代
*
* Metaspace是方法区在HotSpot中实现,他在本地内存,而不是虚拟机内存,class metadata被存储在Metaspace的native memory
*
*永久代:虚拟机加载的类信息;常量池;静态变量;即时编译后的代码
*
* 模拟Metaspace溢出,不断生成类放入元空间,类占据的空间超过Metaspace指定的空间大小
*
*异常现象:
* 多少次后发生异常:183
* java.lang.OutOfMemoryError: Metaspace
* Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
*
*/
private static void metaspaceOOM(String[] args) {
final String[] arg = args;
int i = 0;
try {
while (true){
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMTest.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,arg);
}
});
enhancer.create();
}
} catch (Throwable e) {
System.out.println("多少次后发生异常:"+i);
e.printStackTrace();
throw e;
}
}
static class OOMTest{}; //静态类放在元空间
}
11-04
287
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
08-11
1015
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
07-15