1. 程式人生 > >虛擬機器---4.gc

虛擬機器---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程式碼。長時間執行的指令,比如迴圈等。都有可能成為安全點。