這裏,內存映像工具利用的是Eclipse Memory Analyzee,對Dump出來的堆轉存儲快照進行分析,能夠分清楚究竟是出現了內存泄露(Memory Leak)仍是內存溢出(Memory Overflow)。java
在Eclipse中離線安裝MemoryAnalyzee的步驟以下(因爲在線安裝可能會有網絡問題):網絡
(1)去官網下載離線安裝包:app
即下載MemoyAnalyzer-1.6.1.201611251412.zip包。eclipse
(2)下載以後解壓獲得以下文件內容:jvm
(3)打開Eclipse->Help->Install new Software,以下:ide
將乾菜下載好的路徑引入其中。點擊Ok。工具
(4)點擊Avaliable Software Sites字體
注意:將裏面,全部有關http鏈接的去掉勾選,不然,在更新的時候可能失敗,以下:ui
只要location是http開頭的就去勾選。spa
(5)去掉Contact all update sites during install to findrequired software前面的勾
(6)點擊next,便可成功安裝
那麼:Eclipse Memory Analyzer如何使用呢?
爲了使用MAT,即Memory Analyzer Tool,這裏咱們使用的是Eclipse Memory Anaylyzer須要先明白內存分析的數據源是如何產生的。有兩種方式:
(1)經過jmap(Memory Map for Java)命令生成堆轉儲快照(通常稱爲heapdump或dump文件)
(2)經過JVM參數 -XX:+HeapDumpOnOutOfMemoryError可讓JVM在出現內存溢出異常時Dump出當前內存堆轉存儲快照以便過後進行分析。
這裏先介紹第二種狀況,即JVM中內存溢出後可以自動dump出對轉存儲快照。
編寫一個簡單的堆溢出的代碼以下:
class User{
String name;
String sex;
@Override
public String toString() {
return "User [name=" + name + ", sex=" + sex + "]";
}
}
public class MemoryLeak1 {
public static void main(String[] args) {
List<User> list = new ArrayList<User>();
while(true){
list.add(new User());
}
}
}
分析:上面的代碼中,經過List list中不斷的添加new User()實例,由於list的做用域是和main方法同樣的,而new出來的額User的實例被list中的元素引用,因此,經過while循環new 出來的User不會被GC。所以,致使內存溢出。
爲了分析JVM中內存溢出的狀況,須要添加JVM的參數:-XX:+HeapDumpOnOutOfMemoryError,操做步驟以下:
點擊:Run->DebugConfiguration,在左側列表下的Java Application下對應的你的Java類,好比:我這裏的類是MemoryLeak1,以下:
在Arguments中的VM arguments下填寫:-XX:+HeapDumpOnOutOfMemoryError,而後,點擊Apply,以及點擊Debug,即運行咱們以前寫的那段會內存溢出的代碼。在運行大概兩三分鐘以後,出現以下異常信息:
能夠看到異常信息爲java.lang.OutOfMemoryError:Java heap space,即內存溢出異常。上面的黑色字體是將內存堆轉儲爲dump文件,這裏的dump文件名稱爲:java_pid7568.hprof,其中7568是當前Java程序的進程號。
另外,須要注意的是剛纔咱們生成的dump文件java_pid7568.hprof,這裏的路徑默認是在項目的根路徑下,若是你沒有看到該文件,須要強制刷新當前項目,好比:點擊項目,而後按F5。
接下來,就是將該dump文件經過咱們上面的Memory Analyzer進行分析,步驟以下:
(1)在工具欄上:File->Open File…,選中java_pid7568.hprof文件,並打開
(2)可是產生了以下錯誤:
點擊OK以後,有:
看了上述的問題,大體的意思是說內存溢出錯誤,後面又說了「Runngin Eclipse」,大體猜想應該是系統給Eclipse軟件分配的內存過小,另外,咱們查看了java_pid7568.hprof文件的大小爲3,355,137KB,大概是3g左右。因而,咱們又查看了Eclipse軟件下的eclipse.ini文件:
那麼eclipse.ini中的參數各是什麼意思呢?在理解這些參數以前,須要知道Eclipse這款軟件是由java語言開發的,所以,其自身也須要jvm支持的,那麼它的默認參數配置就在eclipse.ini中,以下:
-startup
plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.300.v20150602-1417
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
512M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
512m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.7
-Xms512m
-Xmx1024m
如上,咱們能夠看到,Eclipse須要java 1.7版本的支持,通常咱們須要安裝Jdk環境,假如咱們刪除掉Jdk環境,那麼會出現以下錯誤:
所以,Eclipse其實本質上就是一個Java程序,咱們能夠經過JVM自帶的jps命令來查看java進程,以下:
咱們輸入jps發現進程id號爲4316,與咱們在Windows任務管理器中看到的eclipse對應的PID是一致的,證實了咱們說的Eclipse本質上也是一個Java程序。
也須要設置最下的堆大小,這裏默認是-Xms512m,最大的堆大小-Xmx1024m,顯然最大的堆大小爲1024m大概是1G左右,明顯小於咱們要打開的文件3G的大小,這裏,咱們將-Xmx設置5120m,以下:
-Dosgi.requiredJavaVersion=1.7
-Xms512m
-Xmx5120m
再次重啓Eclipse,並打開咱們以前的那個大概3G左右的dump文件,則能夠成功打開。
這裏,主要看下「Histogram」,這個會列出每一個類的實例個數。以及「Leak Suspects」分析內存可能產生泄露的緣由。咱們看下:
Histogram:
這裏Class Name是對應類型,Objects是對應實例的個數,很明顯類com.tim.User的實例個數居然達到70,091,071個,那麼後面跟着的兩列:Shallow Heap和Retained Heap是什麼東西?
問題:Shallow Heap和Retained Heap 的區別?
ShallowHeap:Shallow中文的意思是膚淺、淺的意思,則Shallow Heap咱們能夠理解爲淺的表面的堆,是對象自己佔據的內存的大小,不包含其所引用的對象。
RetainedHeap:Retained中文的意思是保留、保存的意思,則Retained Heap咱們能夠理解爲保留、保存的堆,是當前對象大小+當前對象可直接或者間接引用到的對象的大小總和。
分析:上面的Shallow Heap是比較好理解的,而要真正理解Retained Heap須要先理解GC roots是如何工做的?
GCroots:
---------------------