虛擬機器---4.gc
下文純個人理解,有不同意見歡迎指點批評。這些純個人知識梳理總結
講到虛擬機器,大夥肯定會講垃圾回收。方便,自動。
那什麼是垃圾?沒人用了。
那哪裡才有垃圾?記憶體。具體回收都說是堆,其實還有共享方法區;共享方法區,就是放了二進位制檔案的物件和二進位制結構和靜態常量的地方;它怎麼回收確定,想下,這個二進位制檔案進來,是有觸發。既然回收就是全部觸發都沒了。new的物件回收了。沒有例項了。class物件沒人用了。相關靜態的資訊沒人呼叫。基本就可以撤了。
堆:
那虛擬機器怎麼知道哪些是垃圾?第一個問題說沒人用。那它怎麼知道沒人用。原始社會是引用計數演算法,現在是gcroot演算法(可以達到當前);
計數演算法,即某物件每給引用一次,即加一;引用不用了,失效了,即減一;問題來了,A引用B,B引用A;
private class A{
B b;
private void setB(B b) {
this.b = b;
}
}
private class B{
A a;
private void setA(A a) {
this.a = a;
}
}
public static void main(String[] args) {
A a =new test().new A();
B b = new test().new B();
b.setA(a);
a.setB(b);
b = null;
a = null;
System.gc();
堆裡面還互相引用。沒完沒了。宣佈淘汰。
gc roots 演算法(可達性)
由頭開始相下引用。串起來就成一條鏈;倘若頭沒了。就斷了。還是用樓上的程式碼。都給置null。頭斷了。沒用了全回收。
那什麼才可以確定為root。這麼牛逼。
new的,方法區靜態引用,本地方法呼叫的,方法棧的引用;
知道了哪些是垃圾哪些不是垃圾,那又怎麼回收比較好?
先說回收方法有好幾種,
比如標記複製,記憶體分成兩部分,把標記用的複製到另一邊
標記壓縮,標記有用的,往一邊靠攏儲存
根據堆裡面物件存活的生命週期,物件的生命週期很長的很少。很短的很多。
虛擬機器搞了個分代回收。把堆分成了eden區,survival1區,survival2區,old區
eden區,新生區,物件new就進來這裡new。tlab,執行緒本地化,每個執行緒進來2048位元組空間用於建立例項。不夠再拓展;這裡的物件存活時間短。經常需要回收。基本滿了。就進行一次回收。叫做minorgc;經常做。採用的是標記複製。複製到倖存區。
survival區,直接保持一個為空,採用標記複製。把沒用的,幹掉。物件gc次數超過2的4次方次就升級到下一區。
old區,採用的是標記整理。這裡的整理是major gc;old區也有引用其他新的區。那就用卡表標識引用。
full gc是全堆垃圾回收,耗時很長。儘量避免,會引起卡頓。
什麼時候full gc,old不夠了。持久的不夠了。
那gc一個垃圾例項又是具體做了啥程式碼?
其中一步就是呼叫了我們object裡面的finalize方法。且僅僅呼叫一次。如果垃圾回收,呼叫方法,方法重寫由把該例項啟用。那就不再調這個方法。
知道了怎麼區分垃圾跟回收的演算法,那什麼時候區分垃圾跟回收。計算機一直忙個不停。分分鐘就又改變了狀態。虛擬機器採用了stop the world和安全點;
怎麼說呢。stop the world就是此app程序內的執行緒全部暫停,中斷。進行演算法區分垃圾;這就引發出來不同的垃圾收集器;
安全點,也就是不在有堆建立,堆引用。什麼時候呢?本地方法呼叫,不涉及java程式碼。長時間執行的指令,比如迴圈等。都有可能成為安全點。