1、Java堆結構與配置參數
(1)Java7堆內存結構圖
(2) Java8堆內存結構圖
2.2 堆內存調優簡介
(1)調優參數:
(2)如何查看堆內存信息
public static void main(String[] args) { // 返回 Java 虛擬機試圖使用的最大內存量。 long maxMemory = Runtime.getRuntime().maxMemory() ; // 返回 Java 虛擬機中的內存總量。 long totalMemory = Runtime.getRuntime().totalMemory() ; System.out.println("MAX_MEMORY = " + maxMemory + "(字節)、" + (maxMemory / (double)1024 / 1024) + "MB"); System.out.println("TOTAL_MEMORY = " + totalMemory + "(字節)、" + (totalMemory / (double)1024 / 1024) + "MB"); } |
(3)設置堆內存參數
在 VM arguments中設置: -Xms1024m -Xmx1024m -XX:+PrintGCDetails
(4)堆空間溢出
在 VM arguments中設置: -Xms8m -Xmx8m -XX:+PrintGCDetails
public class Oom { public static void main(String[] args) { String str = ""; while (true){ str += str + "OutOfMemoryError"; //在堆中不停的實例化對象 System.out.println(str); } } } |
總結:
1)新生區總結
- 新生區是類的誕生、成長、消亡的區域,一個類在這裏產生,應用,最後被垃圾回收器收集,結束生命。
- 新生區又分爲兩部分: 伊甸區(Eden space)和倖存者區(Survivor pace) ,所有的類都是在伊甸區被new出來的。
- 倖存區有兩個: 0區(Survivor 0 space)和1區(Survivor 1 space)。當伊甸園的空間用完時,程序又需要創建對象,JVM的垃圾回收器將對伊甸園區進行垃圾回收(Minor GC),將伊甸園區中的不再被其他對象所引用的對象進行銷燬。然後將伊甸園中的剩餘對象移動到倖存 0區。若倖存 0區也滿了,再對該區進行垃圾回收,然後移動到 1 區。那如果1 區也滿了呢?再移動到養老區。若養老區也滿了,那麼這個時候將產生MajorGC(FullGC),進行養老區的內存清理。
- 若養老區執行了Full GC之後發現依然無法進行對象的保存,就會產生OOM異常“OutOfMemoryError”。如果出現java.lang.OutOfMemoryError: Java heap space異常,說明Java虛擬機的堆內存不夠。原因有二:
- Java虛擬機的堆內存設置不夠,可以通過參數-Xms、-Xmx來調整。
- 代碼中創建了大量大對象,並且長時間不能被垃圾收集器收集(存在被引用)。
2)永久帶總結
- 永久存儲區是一個常駐內存區域,用於存放JDK自身所攜帶的 Class,Interface 的元數據,也就是說它存儲的是運行環境必須的類信息,被裝載進此區域的數據是不會被垃圾回收器回收掉的,關閉 JVM 纔會釋放此區域所佔用的內存。
- 如果出現java.lang.OutOfMemoryError: PermGen space,說明是Java虛擬機對永久代Perm內存設置不夠。一般出現這種情況,都是程序啓動需要加載大量的第三方jar包。例如:在一個Tomcat下部署了太多的應用。或者大量動態反射生成的類不斷被加載,最終導致Perm區被佔滿。
3)方法區和堆總結
- 實際而言,方法區(Method Area)和堆一樣,是各個線程共享的內存區域,它用於存儲虛擬機加載的:類信息+普通常量+靜態常量+編譯器編譯後的代碼等等,雖然JVM規範將方法區描述爲堆的一個邏輯部分,但它卻還有一個別名叫做Non-Heap(非堆),目的就是要和堆分開。
- 對於HotSpot虛擬機,很多開發者習慣將方法區稱之爲“永久代(Parmanent Gen)” ,但嚴格本質上說兩者不同,或者說使用永久代來實現方法區而已,永久代是方法區(相當於是一個接口interface)的一個實現,jdk1.8的版本中,已經將原本放在永久代的字符串常量池移走。
補充:RUNTIME CONSTANT POOL,運行時常量池
常量池(Constant Pool)是方法區的一部分,Class文件除了有類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池,常量池用於存放編譯期間生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。