java.lang.OutOfMemoryError: Java heap space
當應用程序申請更多的內存,而Java堆內存已經無法滿足應用程序對內存的需要,就會拋出此種異常。
java.lang.OutOfMemoryError: PermGen space及其解決方法
表示Java永久帶(方法區)空間不夠,永久帶用於存放類的字節碼和長常量池,類的字節碼加載后存放在這個區域,這和存放對象實例的堆區是不同的,大多數JVM的實現都不會對永久帶進行垃圾回收,因此,只要類加載的過多就會出現這個問題。一般的應用程序都不會產生這個錯誤,然而,對於Web服務器來講,會產生有大量的JSP,JSP在運行時被動態的編譯成Java Servlet類,然后加載到方法區,因此,太多的JSP的Web工程可能產生這個異常。
java.lang.OutOfMemoryError: unable to create new native thread
創建了太多的線程,而能創建的線程數是有限制的,導致了這種異常的發生。
在Linux下線程使用輕量級進程實現的,因此線程的最大數量也是操作系統允許的進程的最大數量。
java.lang.OutOfMemoryError:GC overhead limit exceeded
是在並行或者並發回收器在GC回收時間過長、超過98%的時間用來做GC並且回收了不到2%的堆內存,然后拋出這種異常進行提前預警,用來避免內存過小造成應用不能正常工作。
java.lang.StackOverflowError ...
JVM的線程由於遞歸或者方法調用層次太多,占滿了線程堆棧而導致的,線程堆棧默認大小為1M。
java.net.SocketException: Too many open files
由於系統對文件句柄的使用是有限制的,而某個應用程序使用的文件句柄超過了這個限制,就會導致這個問題。
工具使用:
jmap命令(Java Memory Map)
map命令可以獲得運行中的jvm的堆的快照,從而可以離線分析堆,以檢查內存泄漏,檢查一些嚴重影響性能的大對象的創建,檢查系統中什么對象最多,各種對象所占內存的大小等等。可以使用jmap生成Heap Dump。
JVM Memory Map命令用於生成heap dump文件,如果不使用這個命令,還可以使用-XX:+HeapDumpOnOutOfMemoryError參數來讓虛擬機出現OOM的時候自動生成dump文件。 jmap不僅能生成dump文件,還可以查詢finalize執行隊列、Java堆和永久代的詳細信息,如當前使用率、當前使用的是哪種收集器等。
常用命令:
-dump
dump堆到文件,format指定輸出格式,live指明是活着的對象,file指定文件名,:live
是可選的。
[root@localhost jdk1.7.0_79]
# jmap -dump:live,format=b,file=dump.hprof 24971
Dumping heap to
/usr/local/java/jdk1
.7.0_79
/dump
.hprof ...
Heap dump
file
created
可以將24971
進程的內存heap以二進制形式(format=b)
輸出出來到dump.hprof
文件里,再配合MAT(內存分析工具)。
-heap
打印heap的概要信息,GC使用的算法,heap的配置及使用情況,可以用此來判斷內存目前的使用情況以及垃圾回收情況Attaching to process ID 8633, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.66-b17
using parallel threads in the new generation. ##新生代采用的是並行線程處理方式
using thread-local object allocation.
Concurrent Mark-Sweep GC ##同步並行垃圾回收
Heap Configuration: ##堆配置情況
MinHeapFreeRatio = 40 ##最小堆使用比例 (GC后如果發現空閑堆內存占到整個預估堆內存的N%(百分比), 則放大堆內存的預估最大值)
MaxHeapFreeRatio = 70 ##最大堆可用比例 (GC后如果發現空閑堆內存占到整個預估堆內存的N%(百分比),則收縮堆內存的預估最大值, 預估堆內存是堆大小動態調控的重要選項之一. 堆內存預估最大值一定小於或等於固定最大值(-Xmx指定的數值). 前者會根據使用情況動態調大或縮小, 以提高GC回收的效率)
MaxHeapSize = 1073741824 (1024.0MB) ##最大堆空間大小 (即-Xmx, 堆內存大小的上限)
NewSize = 89456640 (85.3125MB) ##新生代分配大小(新生代預估堆內存占用的默認值)
MaxNewSize = 348913664 (332.75MB) ##最大可新生代分配大小(新生代占整個堆內存的最大值)
OldSize = 178978816 (170.6875MB) ##老年代大小(老年代的默認大小, default size of the tenured generation)
NewRatio = 2 ##新生代比例(老年代對比新生代的空間大小, 比如2代表老年代空間是新生代的兩倍大小. The ratio of old generation to young generation.)
SurvivorRatio = 8 ##新生代與suvivor的比例(Eden/Survivor的值. 這個值的說明, 很多網上轉載的都是錯的. 8表示Survivor:Eden=1:8, 因為survivor區有2個, 所以Eden的占比為8/10. Ratio of eden/survivor space size. -XX:SurvivorRatio=6 sets the ratio between each survivor space and eden to be 1:6, each survivor space will be one eighth of the young generation.
)
MetaspaceSize = 21807104 (20.796875MB) ##JDK1.8的方法區大小(分配給類元數據空間的初始大小(Oracle邏輯存儲上的初始高水位,the initial high-water-mark ). 此值為估計值. MetaspaceSize設置得過大會延長垃圾回收時間. 垃圾回收過后, 引起下一次垃圾回收的類元數據空間的大小可能會變大)
CompressedClassSpaceSize = 1073741824 (1024.0MB)(類指針壓縮空間大小, 默認為1G)
MaxMetaspaceSize = 17592186044415 MB ##JDK1.8的方法區最大(是分配給類元數據空間的最大值, 超過此值就會觸發Full GC. 此值僅受限於系統內存的大小, JVM會動態地改變此值)
G1HeapRegionSize = 0 (0.0MB)(G1區塊的大小, 取值為1M至32M. 其取值是要根據最小Heap大小划分出2048個區塊. With G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb. Sets the size of a G1 region. The value will be a power of two and can range from 1MB to 32MB. The goal is to have around 2048 regions based on the minimum Java heap size.)
Heap Usage:
New Generation (Eden + 1 Survivor Space): ##新生代(伊甸區 + survior空間)
capacity = 80543744 (76.8125MB)
used = 34725560 (33.11687469482422MB) ##已經使用大小
free = 45818184 (43.69562530517578MB) ##剩余容量
43.11391335371745% used
Eden Space:
capacity = 71630848 (68.3125MB)
used = 29683880 (28.308753967285156MB)
free = 41946968 (40.003746032714844MB)
41.44007900060041% used
From Space:
capacity = 8912896 (8.5MB)
used = 5041680 (4.8081207275390625MB)
free = 3871216 (3.6918792724609375MB)
56.56612620634191% used
To Space:
capacity = 8912896 (8.5MB)
used = 0 (0.0MB)
free = 8912896 (8.5MB)
0.0% used
concurrent mark-sweep generation: ##老年代使用情況
capacity = 178978816 (170.6875MB)
used = 134752632 (128.51012420654297MB)
free = 44226184 (42.17737579345703MB)
75.28971026381133% used
36267 interned Strings occupying 3977048 bytes.
jmap -finalizerinfo pid

B
byte
C
char
D
double
F
float
I
int
J
long
Z
boolean
[ 數組,如[I表示
int
[]
[L+類名 其他對象
如果還需要看更加詳細的信息,則使用:
jmap -dump:format=b,file=dumpFileName pid 直接生成在執行命令時所在的目錄下面。
dump出來的文件可以用MAT、VisualVM等工具查看,也可以使用jhat。
jhat -port 9999 dumpFileName
如果dump出來的文件過大,可能需要指定Xmx(jhat實際啟動了一個web應用)。
jhat -J-Xmx1000m -port 9999 dumpFileName
啟動成功后,則可以通過瀏覽器查看:
ip:port
例如上圖查詢的是長度大於256的int數組。
jmap -histo:live 24971 | grep com.yuhuo 查詢類名包含com.yuhuo的信息
jmap -histo:live 24971 | grep com.yuhuo > histo.txt 保存信息到histo.txt文件
-F 強迫.在pid沒有響應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效.
-h | -help 打印輔助信息
-J<flag> 傳遞參數給jmap啟動的jvm.
pid 需要被打印配相信息的java進程id,可以用jps查問
從安全點日志看,從Heap Dump開始,整個JVM都是停頓的,考慮到IO(雖是寫到Page Cache,但或許會遇到background flush),幾G的Heap可能產生幾秒的停頓,在生產環境上執行時謹慎再謹慎。
live的選項,實際上是產生一次Full GC來保證只看還存活的對象。有時候也會故意不加live選項,看歷史對象。
Dump出來的文件建議用JDK自帶的VisualVM或Eclipse的MAT插件打開,對象的大小有兩種統計方式:
- 本身大小(Shallow Size):對象本來的大小。
- 保留大小(Retained Size): 當前對象大小 + 當前對象直接或間接引用到的對象的大小總和。
看本身大小時,占大頭的都是char[] ,byte[]之類的,沒什么意思(用jmap -histo:live pid 看的也是本身大小)。所以需要關心的是保留大小比較大的對象,看誰在引用這些char[], byte[]。
(MAT能看的信息更多,但VisualVM勝在JVM自帶,用法如下:命令行輸入jvisualvm,文件->裝入->堆Dump->檢查 -> 查找20保留大小最大的對象,就會觸發保留大小的計算,然后就可以類視圖里瀏覽,按保留大小排序了)
轉自:http://www.cnblogs.com/gaojk/articles/3886503.html




4、數據分析



總結
1.如果程序內存不足或者頻繁GC,很有可能存在內存泄露情況,這時候就要借助Java堆Dump查看對象的情況。
2.要制作堆Dump可以直接使用jvm自帶的jmap命令
3.可以先使用jmap -heap
命令查看堆的使用情況,看一下各個堆空間的占用情況。
4.使用jmap -histo:[live]
查看堆內存中的對象的情況。如果有大量對象在持續被引用,並沒有被釋放掉,那就產生了內存泄露,就要結合代碼,把不用的對象釋放掉。
5.也可以使用 jmap -dump:format=b,file=<fileName>
命令將堆信息保存到一個文件中,再借助jhat命令查看詳細內容
6.在內存出現泄露、溢出或者其它前提條件下,建議多dump幾次內存,把內存文件進行編號歸檔,便於后續內存整理分析。
7.在用cms gc的情況下,執行jmap -heap有些時候會導致進程變T,因此強烈建議別執行這個命令,如果想獲取內存目前每個區域的使用狀況,可通過jstat -gc或jstat -gccapacity來拿到。
Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can’t attach to the process
在ubuntu中第一次使用jmap會報錯:Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process
,這是oracla文檔中提到的一個bug:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7050524,解決方式如下:
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope 該方法在下次重啟前有效。
永久有效方法 sudo vi /etc/sysctl.d/10-ptrace.conf 編輯下面這行: kernel.yama.ptrace_scope = 1 修改為: kernel.yama.ptrace_scope = 0 重啟系統,使修改生效。
寫了一個OOM。
public class OOM {
public static void main(String[] args) {
List<StateMachine> list = new ArrayList<StateMachine>();
while(true){
list.add(new StateMachine());
}
}
}
使用如下配置:
-server
-Xms1024m
-Xmx1024m
-Xmn384m
-XX:+UseParallelOldGC
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/Users/yp-tc-m-2777/Desktop/heap.bin