一、方法區的定義
Java虛擬機規範中,將方法區描述為一塊JVM規範的內存。用於用於存儲類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。方法區與Java堆一樣,是被所有線程共享的內存區域。不過,方法區的垃圾回收(Full GC)通常是比較少見的。
二、方法區的常量池
Java虛擬機規範中,常量池是方法區的一部分。常量池是Class文件中的一些字面量和符號引用的集合。在類加載後,將字面量和符號引用都存放在常量池中。同時,在運行期間,也可以通過ldc指令將常量池中的符號引用推入操作數棧中。
public class ConstantPoolExample { public static void main(String[] args){ String str1 = "Hello World"; String str2 = new String("Hello World"); System.out.println(str1 == str2.intern());//True } }
上述代碼中,兩個String對象在編譯期的常量池中,實例化為指向同一個地址的指針,所以判斷為True。
三、方法區的OOM異常
方法區的OOM異常不同於Java堆的OOM異常,因為Java堆溢出後,會出現Out of Memory的異常。而方法區則會出現PermGen Space Exhausted的異常。PermGen Space指的是方法區的永久代,正如它的名字一樣,永久代不會被GC回收。
public class PermGenOOMExample { public static void main(String[] args){ for(int i=1;;i++){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(PermGenOOMExample.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor(){ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); } } }
上述代碼中,我們使用了CGLib庫的Enhancer,通過循環向PermGen Space中不斷注入Class對象,達到PermGen Space溢出,最終會拋出PermGen Space Exhausted異常。
四、方法區的垃圾回收
方法區的垃圾回收是由Full GC來負責的。Full GC會根據對象的GC Roots,來判斷哪些對象需要被回收,並將其所佔用的內存釋放。一般來說,只有在進行類的卸載時,才會進行PermGen Space的垃圾回收。
public class UnloadClassExample { public static void main(String[] args) throws Exception{ MyClassLoader classLoader = new MyClassLoader(); Class clazz = classLoader.loadClass("com.example.MyClass"); Object obj = clazz.newInstance(); Method method = clazz.getMethod("sayHello"); method.invoke(obj); classLoader = null; clazz = null; obj = null; method = null; System.gc(); } } class MyClassLoader extends ClassLoader{ @Override protected Class findClass(String name) throws ClassNotFoundException { byte[] bytes = null;//省略class文件讀取過程 return defineClass(name, bytes, 0, bytes.length); } } class MyClass { public void sayHello(){ System.out.println("Hello World!"); } }
上述代碼中,我們通過自定義的ClassLoader去加載MyClass類,並實例化對象。然後,手動將ClassLoader、Class、obj、method都設為null,再執行System.gc(),就可以進行PermGen Space的垃圾回收。
五、結論
Java方法區是Java虛擬機規範中定義的一塊內存,用於存儲類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。同時,方法區也包含了常量池。當PermGen Space溢出時,會拋出PermGen Space Exhausted異常。垃圾回收通常只在進行類的卸載時進行。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/287358.html