轉載請註明出處 http://www.paraller.com
原文排版地址 點擊獲取更好閱讀體驗java
但垃圾收集效果難以使人滿意:針對常量池的回收以及類的卸載(十分苛刻)web
當Old區再被塞滿,就會觸發FullGC,回收最後能回收的空間算法
局部變量表的內存空間在編譯期就已經分配完成sql
發揮的做用與jvm stack相同,可是爲虛擬機使用到的Native方法服務,hotspot虛擬機將兩個合而爲一數據庫
java程序經過棧上的reference數據操做 堆上的 具體對象windows
虛擬機棧中reference數據稱爲引用
reference類型的數據中儲存的數值表明的是另一塊內存的起始地址,就稱這塊內存是表明着引用
除了 被引用和不被引用兩種狀態 ;JDK1.2以後引入了四種新的概念:強引用、軟引用、弱引用、虛引用數組
主流的方式有兩種,直接指針和使用句柄服務器
訪問句柄: reference中保存着對象的具體地址。優勢是快速。多線程
主要存放類信息,經過CGLib動態構造類會形成OOM異常,好比jsp的構造oracle
每當有一個地方引用+1 ,計數器爲0說明沒有對象引用它 , 存在兩個無用對象相互引用的狀況
主流方式;以GC Roots對象爲起點,根據是否有引用鏈可達判斷;哪些能夠稱爲引用鏈:
PS
:對象如何在被標記回收的時候逃脫: 覆寫finalize方法,將this賦值給某個類變量或者對象的成員變量
指某些對象再也不被應用程序使用,而垃圾收集器(Garbage Collector)卻沒能識別它們是「再也不使用的」。若是那些不使用的對象佔用堆(heap)空間足夠大,使得應用程序沒法知足下一次內存分配需求,就會致使OutOfMemoryError錯誤
內存不夠用了,緣由有幾種,內存泄露只是其中一種。
通常是 OutOfMemoryError :先肯定是內存溢出仍是內存泄露(垃圾回收處理機制)
內存泄露:經過工具查看泄露對象到GC Roots的引用鏈,找到沒法回收的緣由
內存溢出:調到物理內存,判斷是否對象生命週期過長
線程請求的棧深度大於虛擬機棧所容許的最大深度;單線程的時候,不管是棧幀太大仍是虛擬機棧容量過小,當內存沒法分配的時候,虛擬機拋出的都是這個異常
它保存了Java類定義,而且這些類定義是不會變成「無用」的,是嗎?事實上,它們是能夠變成「無用」的。以一個部署到應用程序服務器的Java web程序來講,當該應用程序被卸載的時候,你的EAR/WAR包中的全部類都將變得無用。只要應用程序服務器還活着,JVM將繼續運行,可是一大堆的類定義將再也不使用,理應將它們從永久代(PermGen)中移除。若是不移除的話,咱們在永久代(PermGen)區域就會有內存泄漏。
類加載器(classloader)泄漏的一個可能的場景就是經過運行的線程(而內存泄漏)。當你的程序,或者你的程序使用的第三方庫(我常常遇到這種狀況,好比Quartz)開啓了一些長時間運行的線程。一個例子:一個用於週期性執行代碼的計時器(timer)線程。
若是不解決該線程預期的生命週期問題,咱們直接會遇到麻煩。當你程序的任何一部分啓動一個線程的時候,你要確保它不會比程序活得還要久。在典型的狀況下,開發者要麼不知道本身有責任處理好這個問題,或者忘了寫清理(clean-up)的代碼。
不然,若是應用程序卸載後,線程還在繼續運行,它一般將維持一個到web應用程序的classloader的引用,即咱們所說的contextclassloader。這也就意味着,全部卸載掉的應用程序仍然保存在內存中。怎麼解決?若是是你的程序開啓了新線程,那麼你就應該在卸載的時候關閉它們,這能夠經過使用一個servlet context listener來實現。若是是第三方庫開啓的新線程,你應該搜索它的關閉線程的接口,若是沒有的話,就上報一個bug吧。
另外一個典型的內存泄漏緣由是由數據庫驅動形成的。咱們在和Plumbr一塊兒發佈的demo程序中遇到了這種內存泄漏狀況。它是一個與Sprint MVC一塊兒發佈的、代碼稍微修改過的Pet Clinic程序。讓咱們關注一下當這個應用程序部署到服務器上的時候,發生了什麼:
如今,當從服務器上卸載應用程序的時候,java.sql.DriverManager仍將持有那個引用,不管在HSQLDB庫,或者在Spring framework中,都沒有代碼能夠移除它!正如上面解釋的那樣,一個jdbcDriver對象將持有一個到org.hsqldb.jdbcDriver類的引用,從而持有用於加載應用程序的java.lang.Classloader的一個實例的引用。這個classloader如今仍然引用着應用程序的全部類。在咱們那特殊的demo應用程序中,在程序啓動的時候,須要加載將近2000個類,佔用約10MB永久代(PermGen)內存。這就意味着須要5~10次從新部署,纔會將默認大小的永久代(PermGen)塞滿,而後就會觸發java.lang.OutOfMemoryError: PermGen space錯誤並崩潰。
怎樣解決此問題?一個可能的辦法就是寫一個servlet content listener,用於在應用程序關閉的時候,從DriverManager反註冊HSQLDB驅動。這個方法很直接,可是請記住——你須要在使用該驅動的每個應用程序中都這麼寫。
你的應用程序遇到java.lang.OutOfMemoryError: PermGen space錯誤的緣由不少,究其根本緣由,大多數是因爲object或程序的class loader加載的類的引用已經無用了致使的。對此類問題,你須要採起的補救措施都很是類似,即,首先,找出引用在哪裏被持有;其次,給你的web應用程序添加一個關閉的hook,或者在應用程序卸載後移除引用。你要麼經過servlet context listener,要麼經過第三方庫提供的API來實現這一點。
非jvm運行時數據區;新加入了的NIO類,引入了"Channel"與"Buffer"的I/O方式
經過本地函數庫分配一個堆外內存,而後經過java堆的的對象實例buffer做爲這塊內存的引用進行操做,由於避免了再java heap and native heap之間
進行復制操做,顯著的提升性能,當對於jvm的各個內存總和大於直接內存會報錯
句柄:簡而言之數據的地址須要變更,變更之後就須要有人來記錄管理變更,(就好像戶籍管理同樣),所以系統用句柄來記載數據地址的變動
Presenting the Permanent Generation
[[原創](翻譯)什麼是Java的永久代(PermGen)內存泄漏](http://ju.outofmemory.cn/entr...