JAVA面試匯總(四)JVM(二)

久違的面試匯總JVM的第二篇,還有第三篇,繼續(xù)學習,卷起來,come on baby

6.在JVM中,如何判斷一個對象是否死亡?

(1)通過引用計數(shù)算法,引用計數(shù)器,每當一個地方引用這個對象的時候,計數(shù)器就加1,當引用失效,計數(shù)器就減1;任何時刻計數(shù)器為0的對象就是不可能再被使用了。實現(xiàn)簡單,效率高,但是它很難解決對象的循環(huán)引用問題。
(2)可達性分析算法,這個算法的基本思路是通過一系列稱為“GC Roots”(一組必須活躍的引用)作為起始點,從這些節(jié)點開始向下搜索,搜索走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈時候,那么證明此對象是不可用的。
(3)但是上面兩種算法都不能直接判定對象已經(jīng)死亡,只有g(shù)c時,針對兩種算法都已經(jīng)失效的情況下,對兩個對象回收后才真正算是死亡。

7.Perm Space中保存什么數(shù)據(jù)?會引起OutOfMemory嗎?

(1)全稱是Permanent Generation space,是指內(nèi)存的永久保存區(qū)域。該塊內(nèi)存主要是被JVM用來存儲類的元信息、類變量以及內(nèi)部字符串(interned string)等內(nèi)容。Perm Space使用的JVM內(nèi)存。在JDK1.8被元空(Metaspace)替代。永久代是hotspot VM的實現(xiàn)特有的。
(2)Metaspace沒有存儲字符串常量池,而在jdk7的時候已經(jīng)被移動到了堆中,MetaSpace其他存儲的東西,包括類文件,在JAVA虛擬機運行時的數(shù)據(jù)結(jié)構(gòu),以及class相關(guān)的內(nèi)容,如Method,F(xiàn)ield道理上都與永久代一樣,只是劃分上更趨于合理。metaspace使用的本地內(nèi)存而不是JVM內(nèi)存,因此理論上可以擴展到和本地剩余內(nèi)存一樣大。
(3)當Perm Space中加載的類過多時候,或者存儲的內(nèi)部字符串過多,空間不足時候都可能會導致java.lang.OutOfMemoryError: PermGen space。

8.分派:靜態(tài)分派與動態(tài)分派。

(1)上面第二個問題,講過了
(2)靜態(tài)分派:同樣是將編譯期確定的調(diào)用,重載(Oveload)就是這種類型,在編譯期通過參數(shù)的靜態(tài)類型(注意不是實際類型)作為判斷依據(jù),找到具體的調(diào)用的方法。

public class TestOverLoad {
    public static void main(String[] args) {
        //靜態(tài)類型都是Parent,實際類型分別是Sun和Daughter
        Parent sun = new Sun();
        Parent daughter = new Daughter();
        TestOverLoad test = new TestOverLoad();
        //輸出結(jié)果按照靜態(tài)類型執(zhí)行
        test.testMethod(sun);
        test.testMethod(daughter);
    }
    static abstract class Parent { }
    static class Sun extends Parent { }
    static class Daughter extends Parent { }
    public void testMethod(Parent parent) {
        System.out.println("hello, Parent");
    }
    public void testMethod(Sun sun) {
        System.out.println("hello, Sun");
    }
    public void testMethod(Daughter daughter) {
        System.out.println("hello, Daughter");
    }
}

//輸出
hello, Parent
hello, Parent

(3)動態(tài)分派:運行期根據(jù)實際類型確定方法執(zhí)行版本的分派過程稱為動態(tài)分派。重寫(Override),在運行時期,通過判斷實體的真實類型,判斷具體執(zhí)行哪一個方法。

public class TestOverride {
    public static void main(String[] args) {
        //靜態(tài)類型都是Parent,實際類型分別是Sun和Daughter
        Parent sun = new Sun();
        Parent daughter = new Daughter();
        //這時候輸出結(jié)果按照實際類型找到方法
        sun.testMethod();
        daughter.testMethod();
    }
    static abstract class Parent {
        public void testMethod() {
            System.out.println("hello, Parent");
        }
    }
    static class Sun extends Parent {
        @Override
        public void testMethod() {
            System.out.println("hello, Sun");
        }
    }
    static class Daughter extends Parent {
        @Override
        public void testMethod() {
            System.out.println("hello, Daughter");
        }
    }
}
//輸出
hello, Sun
hello, Daughter

9.請解釋StackOverflowError和OutOfMemeryError的區(qū)別?

(1)當一個線程啟動的時候,jvm就會給這個線程分配一個棧,隨著程序的執(zhí)行,會不斷執(zhí)行方法,因此棧幀會不斷入棧和出棧。然后,一個棧所能容納的棧幀是有限的,當棧幀的數(shù)量超過了棧所允許的范圍的時候(比如遞歸調(diào)用),就會拋出StackOverflowError異常。
(2)程序在執(zhí)行的過程中,需要不斷的在堆內(nèi)存new對象,每new一個對象,就會占用一段內(nèi)存,當對沒有足夠的內(nèi)容分配給對象示例時,就會拋出OutOfMemeryError異常。

10.你有沒有遇到過OutOfMemory問題?你是怎么來處理這個問題的?處理過程中有哪些收獲?

(1)讀取文件時,每條數(shù)據(jù)對應一個實體,創(chuàng)建大量的實體,實體放入集合中,達到一定程度后,又無法通過GC回收被占用的內(nèi)存,最終超過配置的內(nèi)存大小,則會拋出OutOfMemeryError。
(2)從數(shù)據(jù)庫中取出大量數(shù)據(jù),每條數(shù)據(jù)一個實體,實體放入集合中,達到一定量級,超過配置的內(nèi)存大小,會拋出OutOfMemeryError。
(3)實際上就一個根本原因,集合使用的內(nèi)存超過了分配的最大內(nèi)存了。這個時候有兩種方案,分別是擴展分配的最大內(nèi)存,使程序的集合能夠分配到足夠的內(nèi)存,這種情況不推薦,治標不治本,下次集合占用的更多,還是會拋出OutOfMemeryError;另一種方案,使針對集合拆分,例如讀取文件,每次讀取200條,處理完成后,原來的集合設(shè)置null,重新創(chuàng)建新的集合,重新加入200條,這樣GC的時候就可以釋放掉已經(jīng)處理完的實體集合。數(shù)據(jù)庫讀取大量數(shù)據(jù)建議分頁處理,每次處理幾十條,幾百條即可。

感謝各位的閱讀,幫忙點贊,感謝各位。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容