JVM內存區域:
1、虛擬機棧:
方法執行時的內存模型,是線程私有的,生命週期跟線程相同。方法執行時入棧,方法執行完出棧,出棧相當於清空數據,所以這塊不需要GC。
2、本地方法棧:
與虛擬機棧功能非常類似,區別在於虛擬機棧爲虛擬機執行java方法時服務,而本地方法棧爲虛擬機執行本地方法時服務,也不需要GC.
3、程序計數器:
線程獨有,可以看作是當前線程執行的字節碼的指示器。
4、堆:
對象實例和數組都在堆上分配,GC主要對這兩類數據進行回收。
垃圾回收主要方法:
- 標記清除算法
先標記出相應的可回收對象,對可回收的對象進行回收,不用移動數據,有內存碎片。
- 複製算法
把堆分成兩塊區域A和B,區域A負責分配對象,把存活的對象標記出來複製到B區,最後把A區對象全部清理,這樣就解決了內存碎片的問題了。問題:比如堆分配了500M內存,只有250M可用,移動對象效率低下。
- 標記整理法
在標記清除法的基礎上添加了一個整理的過程,將所有的存活對象往一端移動,緊鄰排列,清理另一端的區域,這樣就解決了內存碎片的問題。但是每進行一次垃圾清除都要頻繁移動存活對象,效率低下。
分代收集算法:
大部分的對象都在很短的時間內被回收了(Minor GC就會被回收),分代收集算法根據對象存活週期的不同將堆分成新生代和老年代,默認比例1:2,新生代分爲Eden區,S0,S1,三者的比例爲8:1:1,新生代的GC稱爲Young GC(也叫Minor GC),老年代發生的GC稱爲Old GC (也叫Full GC)。
1、當Eden區將滿時,觸發Minor GC,存活的對象會被移到S0區;當下一次Minor GC時,會把Eden區和S0(S1)中存活的對象移到S1,同時對象年齡+1,當對象的年齡達到了設定的閾值,則晉升到老年代。
2、如果老年代滿了,會觸發Full GC,Full GC會同時回收新生代和老年代(即對整個堆進行GC),造成挺大的性能開銷。
GC期間,只有垃圾回收器線程在工作,其他工作線程則被掛起。(爲啥GC時工作線程會被掛起?一邊收垃圾,另一邊丟垃圾,收拾不乾淨)
新生代的垃圾回收器:Serial, ParNew, ParallelScavenge
老年代的垃圾回收器:CMS, Serial Old, Parallel Old
同時在新老生代的垃圾回收器:G1
如果是運行在桌面環境處於Client模式的,則用Serial + Serial Old 收集器;
如果需要響應時間快,則用ParNew +CMS的搭配;
G1回收器也需要根據吞吐量等要求適當調整相應的JVM參數。
沒有最牛的技術,只有最合適的使用場景。