1. 程式人生 > >java8中使用Metaspace就不會出現OOM嗎?

java8中使用Metaspace就不會出現OOM嗎?

前言:在java8中,Metaspace的出現,使我們現在不會再遇到java.lang.OutOfMemoryError: PermGen問題,但是我們要記住,這個新特性並不會使類載入導致的記憶體洩露就此消失。

(一)Metaspace的簡單介紹
(1)記憶體模型:大部分類元資料都在本地記憶體分配,用於描述類元資料的“klasses“已經被移除。
(2) 容量:預設情況下只受本地記憶體限制,但是我們可以限制。

(二)接下來看看Metaspace會不會出現OOM
我們可以通過動態代理來生成大量的代理類資訊填充元資料區。程式碼如下

public interface MetaspaceFacade {
    void
method(String input); }
public class MetaspaceFacadeImpl implements MetaspaceFacade {

    public void method(String name) {
    }
}
public class MetaspaceFacadeInvocationHandler implements InvocationHandler {

    private Object classAImpl;

    public MetaspaceFacadeInvocationHandler(Object impl) {
       this
.classAImpl = impl; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(classAImpl, args); } }
public class ClassMetadataLeakSimulator {

    private static Map<String, MetaspaceFacade> classLeakingMap = new
HashMap<String, MetaspaceFacade>(); private final static int NB_ITERATIONS_DEFAULT = 50000; /** * @param args */ public static void main(String[] args) { System.out.println("Class metadata leak simulator"); int nbIterations = NB_ITERATIONS_DEFAULT; try { for (int i = 0; i < nbIterations; i++) { String fictiousClassloaderJAR = "file:" + i + ".jar"; URL[] fictiousClassloaderURL = new URL[] { new URL(fictiousClassloaderJAR) }; URLClassLoader newClassLoader = new URLClassLoader(fictiousClassloaderURL); MetaspaceFacade t = (MetaspaceFacade) Proxy.newProxyInstance(newClassLoader, new Class<?>[] { MetaspaceFacade.class }, new MetaspaceFacadeInvocationHandler(new MetaspaceFacadeImpl())); classLeakingMap.put(fictiousClassloaderJAR, t); } } catch (Throwable any) { System.out.println("ERROR: " + any); } System.out.println("Done!"); } }

1,首先不進行任何設定(需要保證堆大小),執行得到下面的截圖
這裡寫圖片描述
可以看出,Metaspace進行了動態擴充套件,本地記憶體達到了300多M,載入超過5萬個類後還沒有出現OOM事件。接下來我們限定一下

2,虛擬機器引數配置如下:-Xmx2g -Xms2g -Xmn1g -XX:+PrintGCDetails -XX:MaxMetaspaceSize=128m,執行得到下面的截圖
這裡寫圖片描述
可以看出,此時Metaspace被耗盡,將會丟擲OOM事件。這裡要注意MaxPermSize的區別,MaxMetaspaceSize並不會在jvm啟動的時候分配一塊這麼大的記憶體出來,而MaxPermSize是會分配一塊這麼大的記憶體的。

那麼問題來了,如果我們不設定MaxMetaspaceSize,那麼我們能用到系統的全部記憶體嗎??
metaspace很可能因為被無止境使用而被OS Kill,所以一般還是設定比較好。