JVM你必需知道的基礎

引言:

昨天寫了一篇關於java中對象生死的問題,主要目的是想讓大家感覺一下我所感受到的東西:其實jvm也非常有意思,甚至對象的創建與消亡都可能觸動你的心絃。所以,今天我打算深入學習一下jvm必要基礎(上一篇博文也略有涉及),主要介紹一下JVM運行時各個區域的區別和作用,本來想羅列一張表的,但是篇幅會很醜,所以我就拆開一部分一部分來說。同樣的,我會先在技術點寫一些博文涉及到以外的知識點,方便大家理解。筆者目前整理的一些blog針對面試都是超高頻出現的。大家可以點擊鏈接:http://blog.csdn.net/u012403290

技術點:

1、棧:

又名堆棧,它是一種運算受限的線性表。其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱爲棧頂,相對地,把另一端稱爲棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成爲新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰的元素成爲新的棧頂元素。 –百度詞條

上面我引用了百度詞條的解釋幫助大家理解,其實棧就類似於往一根底端封閉的管子中放彈珠,放進去的過程叫壓棧,拿出來最上面那個叫出棧。但是如果你要拿管子最底下那個彈珠呢?你就需要一顆顆把上面的拿出來,直到拿到最下面那顆。這就是棧的先進後出的規則。

2、棧溢出與內存溢出:

棧溢出:線程請求的棧深度大於虛擬機所允許的深度就會產生棧溢出。這樣說可能不好理解,換種說法就是,從技術點1可以知道棧是一種線性表,如果棧內存容量很小,那麼我卻定義了大量的需要被棧存儲的數據,那麼這個線性表的長度就不夠用了就會導致棧溢出。
內存溢出:如果沒有獲得足夠的內存那麼就會導致內存溢出。

3、線程隔離與現場共享:

簡單來說就是線程與線程之間存不存在共享資源或者說線程之間是否相互影響,如果一個線程的執行與其他線程互不影響,獨立存儲,那麼這個線程就是隔離的。

4、java的native方法:

簡單來說就是java調用了不是java代碼的接口。因爲java並不是萬能的,必要時候可能需要別的語言合併開發,那麼java在調取別的語言的接口的時候就是執行了native方法。

5、新生代,老年代,永久代:

簡單來說,新生代對象是“朝生夕死“的,GC回收很快;老年代的話回收頻率就會變得相對較慢,而且是要指定的一些GC過程纔會進入回收。永久代(一般指方法區),基本不會回收。

JVM必要基礎

現在進入核心部分,我們以類比的方式進行闡述,請各位注意比較。現引入一張昨天的圖:

這裏寫圖片描述

比較模塊主要有:①作用,②消費內存,③線程關係,④異常,⑤所包含重要模塊

1、程序計數器:①作用:作爲行號指示器,用於選取下一條需要執行的字節碼指令。②消費內存:確定大小,很小的內存空間。③線程關係:線程隔離。④異常:無。⑤所包含重要模塊:無。

2、java虛擬機棧:①作用:存放在編譯期間已知的各種基本數據類型(boolean,byte,char,int,short,float,long,double),對象的引用和指向一條字節碼指令的地址。②消費內存:編譯期間確定內存大小。③線程關係:線程隔離。④異常:棧溢出與內存溢出。⑤所包含重要模塊:棧幀,局部變量表。

注意:我這裏對虛擬機棧做一點更清楚的解釋,它們的包含關係是:虛擬機棧>棧幀>局部變量表。而我們一般來說的棧,其實是指局部變量表,因爲局部變量表用語存儲對象引用。每一個方法都會有一個棧幀,這個棧幀就是我前面的比喻“彈珠“。每個方法在執行過程中都會創建一個棧幀,方法調用到執行完成就是棧幀在虛擬機棧中從入棧到出棧的過程。

3、本地方法棧:①作用:類似於java的虛擬機棧,不過它主要用於執行Native方法。②消費內存:編譯期間確定內存大小。③線程關係:線程隔離。④異常:棧溢出與內存溢出。⑤所包含重要模塊:無。

4、java堆(新生代與老年代):①作用:存儲對象實例。②消費內存:運行期間動態分配。③線程關係:線程共享。④異常:內存溢出。⑤所包含重要模塊:無。

注意:這裏說明一個很亂的問題,對象一定是在堆上分配麼?這個答案是否定的,因爲隨着計算機技術的發展,在棧上分配對象也都可以。我舉個栗子,有個技術叫逃逸分析:它是指當一個對象在方法中被定義之後,它如果被外部方法引用,則稱爲逃逸。那麼,如果這個對象不發生逃逸,它的生命週期就和它的引用存活一樣長的時間,在引用出棧的時候就可以順帶銷燬對象了,這樣以來既可以加快訪問速度,也可以減小GC機制的壓力。是不是很奇妙?

5、方法區(永久代):①作用:存儲已被加載的類信息,常量,靜態變量和即時編譯後的代碼。②消費內存:運行期間動態分配。③線程關係:線程共享。④異常:內存溢出。⑤所包含重要模塊:運行時常量池。

下面這張圖大致說明訪問對象的過程和各個模塊之間的調度關係(不止如下一種訪問方式):

這裏寫圖片描述

注意:常量池用於存放編譯期的各種字面量和符號引用。爲什麼要放到常量池呢?因爲它就和我們現在的緩存類似,直接可以通過常量池讀取,提升系統速度和性能。比如我們經常使用的String str=“hello”,這個hello就是放在常量池中。

如果博文存在什麼問題,或者有什麼想法,可以聯繫我呀,下面是我的微信二維碼:

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章