一塊很小的內存空間html
一般存放基本數據類型,對象引用(一個指向對象起始地址的引用指針或一個表明對象的句柄),reeturnAddress類型(指向一條字節碼指令的地址)java
與虛擬機棧類似,主要爲虛擬機使用到的Native方法服務,在HotSpot虛擬機中直接把本地方法棧與虛擬機棧二合一linux
和虛擬機棧同樣可能拋出StackOverflowError和OutOfMemoryError異常。算法
java堆是被全部線程共享的一塊內存區域,在虛擬機啓動時建立。此區域的惟一目的就是存儲對象實例。java堆是垃圾收集器管理的主要區域。java堆還能夠細分爲:新生代與老年代。再細一點有Eden空間、Form Survivor空間、To Survivor空間等。數據庫
直接內存並非虛擬機運行時數據區的一部分,也不是java虛擬機規範中定義的內存區域,是jvm外部的內存區域,這部分區域也可能致使OutOfMemoryError異常。ubuntu
其實這些算法和OOM沒有太大關係,OOM產生的緣由很簡單,就是須要內存的時候沒有內存了,可是對垃圾回收機制的理解可讓咱們知道-Xmx -Xms Xmn – MaxPermSize參數該怎麼樣設置,避免頻繁full-GC(Full-GC會形成app短暫停頓,此時app是不會響應任何客戶端請求的),而且合理設置參數.(1對於緩存過多的系統能夠增大-Xmx,經過減少Xmn調整新生代年老代比例,2對於瞬時對象過多的系統,年老代的heap能夠不用分配那麼大)緩存
HotSpot JVM一共有4個垃圾回收器:Serial(串行)、Parallel / Throughput(並行)、CMS(併發)、and the new kid on the block G1(G1)。HotSpot默認使用Parallel / Throughput回收器,但它經常不是你運行程序的最佳選擇。好比CMS和G1會使GC停頓(GC pause)發生的頻率下降,可是對於每次停頓所花費的時間,極可能比Parallel回收器更長。在使用相同大小堆內存的狀況下,Parallel回收器能帶來更高的吞吐量。因此,須要根據可接受的GC停頓頻率和持續時間,選擇合適的垃圾回收器。
GC算法自己能夠是串行的(單線程),也能夠是並行的(多線程)。所以當咱們提到併發的GC時,並不表明它是並行完成的,相反當提到串行GC時,也並不意味着就必定會出現GC停頓。在GC的世界中,併發和並行是兩個徹底不一樣的概念。併發針對的是GC週期,而並行針對GC算法自身。tomcat
Java 7中引入了G1回收器,它是JVM垃圾回收器中最新的組件。G1最大的優點就是解決了CMS中常見的內存碎片問題:GC週期會從老年代(Old Generation)中釋放內存塊,結果內存變得像瑞士奶酪那樣千瘡百孔,直到JVM對其無從下手了,纔不得不停下來處理這些碎片。可是某些狀況下其餘回收器可能比G1有更好的表現,這徹底取決於你的需求(能夠經過GC日誌分析)服務器
如上圖所示,爲Java堆中的各代分佈。多線程
除了程序計數器外,虛擬機內存的其餘幾個運行時區域都有發生OutOfMemoryError(OOM)異常的可能,
Java Heap 溢出
通常的異常信息:java.lang.OutOfMemoryError:Java heap spacess
java堆用於存儲對象實例,咱們只要不斷的建立對象,而且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象,就會在對象數量達到最大堆容量限制後產生內存溢出異常。
出現這種異常,通常手段是先經過內存映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,重點是確認內存中的對象是不是必要的,先分清是由於內存泄漏(Memory Leak)仍是內存溢出(Memory Overflow)。
若是是內存泄漏,可進一步經過工具查看泄漏對象到GC Roots的引用鏈。因而就能找到泄漏對象時經過怎樣的路徑與GC Roots相關聯並致使垃圾收集器沒法自動回收。
若是不存在泄漏,那就應該檢查虛擬機的參數(-Xmx與-Xms)的設置是否適當。
若是線程請求的棧深度大於虛擬機所容許的最大深度,將拋出StackOverflowError異常。
若是虛擬機在擴展棧時沒法申請到足夠的內存空間,則拋出OutOfMemoryError異常
這裏須要注意當棧的大小越大可分配的線程數就越少。
異常信息:java.lang.OutOfMemoryError:PermGen space
若是要向運行時常量池中添加內容,最簡單的作法就是使用String.intern()這個Native方法。該方法的做用是:若是池中已經包含一個等於此String的字符串,則返回表明池中這個字符串的String對象;不然,將此String對象包含的字符串添加到常量池中,而且返回此String對象的引用。因爲常量池分配在方法區內,咱們能夠經過-XX:PermSize和-XX:MaxPermSize限制方法區的大小,從而間接限制其中常量池的容量。
方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。
異常信息:java.lang.OutOfMemoryError:PermGen space
方法區溢出也是一種常見的內存溢出異常,一個類若是要被垃圾收集器回收,斷定條件是很苛刻的。在常常動態生成大量Class的應用中,要特別注意這點
生成Dump快照文件:
先經過內存映像分析工具(如Eclipse的Memory Analyzer)進行分析,常見的狀況有:
1 先採用jps 或ps -ef|grep xxx找到 JAVA 程序的PID
2 利用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid 找到佔用CPU最高的的線程列表
如 ps -mp 2633 -o THREAD,tid,time | sort -rn |head -10
3 將線程ID轉化爲十六進制 printf "%x\n" 21742,好比獲得: aaee
4 打印線程的堆棧信息 jstack 2633 |grep e18 -A 30 若是運行在64位JVM上,可能須要指定-J-d64命令選項參數。
5 根據提示,調整代碼,從新發布程序
1 jmap -permstat pid
打印進程的類加載器和類加載器加載的持久代對象信息,輸出:類加載器名稱、對象是否存活(不可靠)、對象地址、父類加載器、已加載的類大小等信息
2 jmap -heap pid
使用jmap -heap pid查看進程堆內存使用狀況,包括使用的GC算法、堆配置參數和各代中堆內存使用狀況
3 jmap -histo[:live] pid
使用jmap -histo[:live] pid查看堆內存中的對象數目、大小統計直方圖,若是帶上live則只統計活對象
4 jmap -dump:format=b,file=dumpFileName pid
用jmap把進程內存使用狀況dump到文件中,再用jhat分析查看。jmap進行dump命令格式以下 jmap -dump:format=b,file=/tmp/dump.dat 21711
注意若是Dump文件太大,可能須要加上-J-Xmx512m這種參數指定最大堆內存,即jhat -J-Xmx512m -port 9998 /tmp/dump.dat
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
vmid是Java虛擬機ID,在Linux/Unix系統上通常就是進程ID。interval是採樣時間間隔。count是採樣數目。好比下面輸出的是GC信息,採樣時間間隔爲250ms,採樣數爲4:
jstat -gc pid 60000 60
root@ubuntu:/# jstat -gc 21711 250 4 S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 192.0 192.0 64.0 0.0 6144.0 1854.9 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649 192.0 192.0 64.0 0.0 6144.0 1972.2 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649
各列的含義:
S0C、S1C、S0U、S1U:Survivor 0/1區容量(Capacity)和使用量(Used) EC、EU:Eden區容量和使用量 OC、OU:年老代容量和使用量 PC、PU:永久代容量和使用量 YGC、YGT:年輕代GC次數和GC耗時 FGC、FGCT:Full GC次數和Full GC耗時 GCT:GC總耗時
若是分析結果代表執行GC的時間只有0.1-0.3秒,那你就不必浪費時間去進行GC優化。可是,若是GC的執行時間是1-3秒,或者超過10秒,GC將勢在必行。
hprof可以展示CPU使用率,統計堆內存使用狀況。
不多使用,常用java core來分析
Java程序運行時,有時會產生JavaCore及HeapDump文件,它通常發生於Java程序遇到致命問題的狀況下。
爲了可以保留Java應用發生致命錯誤前的運行狀態,JVM在死掉前產生兩個文件,分別爲JavaCore及HeapDump文件。
可使用IBM的HeapAnalyzer工具分析
HeapDump文件是一個二進制文件,它保存了某一時刻JVM堆中對象使用狀況,這種文件須要相應的工具進行分析,如IBM Heap Analyzer這類工具。這類文件最重要的做用就是分析系統中是否存在內存溢出的狀況。
可使用IBM的jca工具分析
一般狀況下,頻繁發生core dump是因爲如下兩類緣由致使: 內存泄漏、內存碎片的問題
JavaCore文件主要保存的是Java應用各線程在某一時刻的運行的位置,即JVM執行到哪個類、哪個方法、哪個行上。它是一個文本文件,打開後能夠看到每個線程的執行棧,以stack trace的顯示。經過對JavaCore文件的分析能夠獲得應用是否「卡」在某一點上,即在某一點運行的時間太長,例如數據庫查詢,長期得不到響應,最終致使系統崩潰等狀況。
可使用IBM的ga(IBM Pattern Modeling and Analysis Tool for Java Garbage Collector) 工具分析
只要在WebSphere管理控制檯的java進程屬性裏勾選「詳細垃圾回收」
GC優化的最基本原則是將不一樣的GC參數用於2臺或者多臺服務器,並進行對比,並將那些被證實提升了性能或者減小了GC執行時間的參數應用於服務器。請謹記這一點。
GC優化須要考慮的Java參數
定義 |
參數 |
描述 |
堆內存空間 |
-Xms |
Heap area size when starting JVM 啓動JVM時的堆內存空間。 |
-Xmx |
Maximum heap area size 堆內存最大限制 |
|
新生代空間 |
-XX:NewRatio |
Ratio of New area and Old area 新生代和老年代的佔比 |
-XX:NewSize |
New area size 新生代空間 |
|
-XX:SurvivorRatio |
Ratio ofEdenarea and Survivor area 伊甸園空間和倖存者空間的佔比 |
我在進行GC優化時常用-Xms,-Xmx和-XX:NewRatio。-Xms和-Xmx是必須的。你如何設定NewRatio 會對GC性能產生十分顯著的影響。有些人可能會問如何設定Perm區域的大小?你能夠經過-XX:PermSize 和-XX:MaxPermSize參數來設定,
當OutOfMemoryError 錯誤發生而且是因爲Perm空間不足致使時,另外一個可能影響GC性能的參數是GC類型。下表列出了全部可選的GC類型(基於JDK6.0)
GC類型可選參數
分類 |
參數 |
備考 |
Serial GC |
-XX:+UseSerialGC |
|
Parallel GC |
-XX:+UseParallelGC |
|
Parallel Compacting GC |
-XX:+UseParallelOldGC |
|
CMS GC |
-XX:+UseConcMarkSweepGC |
|
G1 |
-XX:+UnlockExperimentalVMOptions |
在JDK6中這兩個參數必須同時使用 |
除了G1 GC,能夠經過每種類型第一行的參數來切換GC類型。最經常使用的GC類型是Serial GC。他專門針對客戶端系統進行了優化。
影響GC性能的參數有不少,可是上面提到的參數會帶來最顯著的效果。請牢記,設定過多的參數不必定會減小GC執行時間
成爲Java GC專家—如何優化Java垃圾回收機制的系列文章
http://www.importnew.com/author/wangxiaojie
http://www.importnew.com/1993.html
http://www.importnew.com/2057.html
http://www.importnew.com/3146.html
http://www.importnew.com/3151.html