GC將堆里的對象分為新生代,老年代,持久代。新生代有一個Eden區,兩個survivor區。新生成的對象直接放在Eden區,Eden區滿了就放進survivor1,當survivor1滿了就會出發一次Minor GC:將存活的對象放入survivor2,然后清空Eden和survivor1,再將survivor區的交換,保證survivor2為空。當survivor2不足以存放Eden和survivor1的存活對象時,就會放入老年區。較大的對象和長期存活的對象直接進入老年區。當即將進入老年區的對象超過老年區剩余大小時,觸發一次full GC。 頻率上說,Minor GC較頻繁,full GC不頻繁。 持久代會存放一些靜態值和方法。
其實就是對什么對象進行回收。比較標準的回答是:從root搜索不到,而且經過第一次標記、清理后,仍然沒有復活的對象。 gc roots: 1. 虛擬機棧中的引用的對象 2. 方法區中靜態屬性引用的對象,常量引用的對象 3. 本地方法棧中JNI(即一般說的Native方法)引用的對象。
新生代:復制清理。 老年代:標記-清除、標記-壓縮
堆中每個對象都有一個計數變量,每當有引用指向該對象時,變量加1,每當一個引用超出生命周期或指向其他對象時,變量減一。當為0時,會被認為是垃圾。 - 優點:簡單,效率高 - 缺點:無法識別互相引用但不能從外部訪問的對象。
從root開始掃描,對存活的對象進行標記,再掃描整個空間的對象,對沒有標記的對象進行回收. - 缺點:會造成內存碎片。
在標記-清除后,將所有對象向空閑區移動,并更新指針。成本更高了。 - 優點:解決了內存碎片 - 缺點:增加句柄,成本高
將內存空間分為對象面和空閑面。當對象面滿了,就將存活的對象復制到空閑面。然后清除對象面。如果按照1:1的比例分配空間,那太浪費了。如果對象生存期都非常短,那可以減少空閑區空間,可以節省空間。如主流的虛擬機上新生代Eden:Survivor1:Survivor2=8:1:1。 - 優點:解決了內存碎片和增加句柄的問題。 - 缺點:對于生存期長的對象,浪費空間。
這是我看了網上一些大神的博客和一些學長的理解后,自己整理的我自己關于java gc的大致認識。希望可以解決你的一些小困惑。
新聞熱點
疑難解答