1、JVM內存模型
堆,棧,本地方法棧,方法區,程序計數器
2、GC
新生代收集器:Serial(單線程)、ParNew、Parallel Scavenge;
老年代收集器:Serial Old(單線程)、Parallel Old、CMS;
整堆收集器:G1
整體使用的分代回收算法,年輕代使用copy算法,年老代使用標記管理算法,都可以避免產生碎片。
-
觸發GC的時機
最后總結一下什么時候會觸發一次GC,個人經驗看,有三種場景會觸發GC:
1、第一種場景應該很明顯,當年輕代或者老年代滿了,Java虛擬機無法再為新的對象分配內存空間了,那么Java虛擬機就會觸發一次GC去回收掉那些已經不會再被使用到的對象
2、手動調用System.gc()方法,通常這樣會觸發一次的Full GC以及至少一次的Minor GC
3、程序運行的時候有一條低優先級的GC線程,它是一條守護線程,當這條線程處於運行狀態的時候,自然就觸發了一次GC了。
-
年輕代(Young Generation)
1.所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。
2.新生代內存按照8:1:1的比例分為一個eden區和兩個survivor(survivor0,survivor1)區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在Eden區中生成。回收時先將eden區存活對象復制到一個survivor0區,然后清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活對象復制到另一個survivor1區,然后清空eden和這個survivor0區,此時survivor0區是空的,然后將survivor0區和survivor1區交換,即保持survivor1區為空, 如此往復。
3.當survivor1區不足以存放 eden和survivor0的存活對象時,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都進行回收
4.新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)
年老代(Old Generation)
1.在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命周期較長的對象。
2.內存比新生代也大很多(大概比例是1:2),當老年代內存滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代對象存活時間比較長,存活率標記高。
持久代(Permanent Generation)
用於存放靜態文件,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。
-
有如下原因可能導致Full GC:
1.年老代(Tenured)被寫滿
2.持久代(Perm)被寫滿
3.System.gc()被顯示調用
4.上一次GC之后Heap的各域分配策略動態變化
-
Java有了GC同樣會出現內存泄露問題
1.靜態集合類像HashMap、Vector等的使用最容易出現內存泄露
2.各種連接,數據庫連接,網絡連接,IO連接等沒有顯示調用close關閉,不被GC回收導致內存泄露。
3.監聽器的使用,在釋放對象的同時沒有相應刪除監聽器的時候也可能導致內存泄露。