想辦法讓 Jvm 的各個分區 OOM
堆內存#
堆內存溢出主要是一直創建物件,但是又不能被 GC 回收(可達性分析,GC Root 和物件之間有可達路徑)就會溢出了。
參數:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError
byte[] a = new byte[21 * 1024 * 1024];
加上HeapDumpOnOutOfMemoryError
可以 dump 出日誌,便於後續分析 OOM 的問題所在
堆疊內存溢出#
虛擬機堆疊裡有個局部變數表,通過不斷創建局部變數,可以讓它爆掉
(這裡沒成功 OOM, 不懂是 Jvm 的原因還是什麼)
參數: -Xss1m -XX:+HeapDumpOnOutOfMemoryError
public void StackOOM() {
while (true) {
Thread thread = new Thread(this::job);
thread.start();
}
}
private void job() {
while (true) {
}
}
方法區溢出#
方法區用於存放類的資訊,所以想要溢出方法區,只要動態地生成大量的類就可以了。比較簡單地生成類的方法是通過使用 Cglib 生成。所以說
有使用 Cglib 的專案是有可能出現方法區溢出異常的,比如 Spring 的 Aop, 如果大量的增強類,會產生很多的類,方法區的大小不夠就會產生異常。
如果使用-XX:PermSize=1M -XX:MaxPermSize=1M
, 要確保 jvm 版本低於 8,因為 Java1.8 移除了永久代,類資訊放在了 Meta Space。
控制 Meta space 用 -XX:MetaspaceSize
和 -XX:MaxMetaspaceSize
參數:-XX=10m -XX=10m -Xmx20m -Xms10m
while (true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestMain.class);
enhancer.setUseCache(false);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects));
enhancer.create();
}
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
直接內存溢出#
直接內存溢出通常出現在 Nio 出現的地方,比如 Netty。可以通過 unsafe 方法直接請求系統內存來模擬直接內存溢出。
參數: -XX=10M -XX:+HeapDumpOnOutOfMemoryError
Field field = Unsafe.class.getDeclaredFields()[0];
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
while (true) {
unsafe.allocateMemory(1 * 1024 * 1024);
}
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)