【VisualVM 簡明教程】(3):分析PermGenOOM

PermGen Space是Oracle-Sun Hotspot纔有的,同類產品Oralce JRockit, IBM J9, Taobao JVM 是沒有的,在Java8中永久區(PermGen)已經變成元空間(Metaspace),這裏懷舊一下。html

案例:PermGen OOM

設置VM啓動參數 -XX:PermSize=5m -XX:MaxPermSize=5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\dump 運行下面代碼(這裏用的Maven倉庫下的jar包,根據本身狀況來),經過不斷的動態加載類(Spring常常幹這樣的事情),形成PermGen OOM. 通常JVM默認PermGen大約是80M左右(和環境也有點關係,不過八九不離十),能夠經過jmap -heap pid 查看,爲何那麼小能夠看下這個回答java


import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
 
 
public class PermGen {
 
    private static List<Object> insList = new ArrayList<Object>();
 
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, MalformedURLException, InterruptedException {
        permLeak();
    }
 
    private static void permLeak() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, MalformedURLException, InterruptedException{
        for (int i = 0; i < 1000 ; i++) {
            URL[] urls = getURLS();
            URLClassLoader loader = new URLClassLoader(urls,null);
            Class<?> logfClass = Class.forName("org.apache.commons.logging.LogFactory",true,loader);
            Method getLog = logfClass.getMethod("getLog", String.class);
            Object result = getLog.invoke(logfClass, "TestPermGen");
            insList.add(result);
            System.out.println(i + " : " + result);
            Thread.sleep(100);
        }
    }
 
    private static URL[] getURLS() throws MalformedURLException{
        File libDir = new File("D:\\HHSZXA\\.m2\\repository\\commons-logging\\commons-logging\\1.1.1");
        File[] subFiles = libDir.listFiles();
        int count = subFiles.length;
        URL[] urls = new URL[count];
        for (int i = 0; i < count ; i++) {
            urls[i] = subFiles[i].toURI().toURL();
        }
        return urls;
    }
 
 
}

輸出:apache

0 : org.apache.commons.logging.impl.Jdk14Logger@2babbba1
1 : org.apache.commons.logging.impl.Jdk14Logger@5d08e435
2 : org.apache.commons.logging.impl.Jdk14Logger@30d46b95
3 : org.apache.commons.logging.impl.Jdk14Logger@4ec4f498
4 : org.apache.commons.logging.impl.Jdk14Logger@7dbc345a
5 : org.apache.commons.logging.impl.Jdk14Logger@7ee361ad
6 : org.apache.commons.logging.impl.Jdk14Logger@7d94a8eb
java.lang.OutOfMemoryError: PermGen space
Dumping heap to d:\dump\java_pid3276.hprof ...
Heap dump file created [2648239 bytes in 0.016 secs]
Exception in thread "Reference Handler" Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at PermGen.permLeak(PermGen.java:25)
    at PermGen.main(PermGen.java:16)
Caused by: java.lang.OutOfMemoryError: PermGen space
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:792)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at org.apache.commons.logging.LogFactory.createFactory(LogFactory.java:1131)
    at org.apache.commons.logging.LogFactory$2.run(LogFactory.java:1065)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.commons.logging.LogFactory.newFactory(LogFactory.java:1062)
    at org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:650)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:704)
    ... 6 more
java.lang.OutOfMemoryError: PermGen space
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:140)

經過控制檯信息,能夠初步斷定是方法區OOM,緣由是經過URLClassLoader類加載器加載某個動態類,這個動態類是由調用org.apache.commons.logging.LogFactory.getLog方法生成的,同時能夠看到引發的錯誤的代碼行數PermGen.java:25微信

首先看摘要
性能

其中1131行代碼,就是實例化某個類,這個類是什麼,咱們能夠改變日誌輸出級別,或者直接打印。url

一切真相大白,有興趣更深刻的童鞋,歡迎討論。spa

解決方案

  • 增大PermGen區域大小
  • 讓JVM清除再也不使用的類

-XX:+CMSClassUnloadingEnabled.net

參考資料


感謝您的耐心閱讀,若是您發現文章中有一些沒表述清楚的,或者是不對的地方,請給我留言,你的鼓勵是做者寫做最大的動力,
若是您認爲本文質量不錯,讀後以爲收穫很大,不妨小額贊助我一下,讓我更有動力繼續寫出高質量的文章。日誌

  • 支付寶

  • 微信

做 者 : @mousycodercode

原文出處 : http://mousycoder.com/2016/01...

創做時間:2016-1-15

更新時間:2016-1-15

相關文章
相關標籤/搜索