阿里學習專題-性能調優專題二(JVM基礎知識)

JVM調優

古人云:知其然,更要知其所以然。

這裏我們介紹的是Jvm,那麼首先我們瞭解jvm的基礎知識,什麼是jvm,jvm相關的知識有哪些?

1)JVM是什麼?

引用官方介紹:JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。

Java虛擬機本質上就是一個程序,當它在命令行上啓動的時候,就開始執行保存在某字節碼文件中的指令。Java語言的可移植性正是建立在Java虛擬機的基礎上。任何平臺只要裝有針對於該平臺的Java虛擬機,字節碼文件(.class)就可以在該平臺上運行。這就是“一次編譯,多次運行”。

Java虛擬機不僅是一種跨平臺的軟件,而且是一種新的網絡計算平臺。該平臺包括許多相關的技術,如符合開放接口標準的各種API、優化技術等。Java技術使同一種應用可以運行在不同的平臺上。Java平臺可分爲兩部分,即Java虛擬機(Java virtual machine,JVM)和Java API類庫。 

2)體系結構

每個Java程序都離不開Java虛擬機,Java程序的運行依靠具體的Java虛擬機實例。在Java虛擬機規範中,分

別用子系統、內存區、數據類型以及指令這幾個術語來描述的。這些組成部分一起展示出一個抽象化的虛擬機內部的抽象體系結

Java虛擬機主要分爲五大模塊:類裝載器子系統、運行時數據區、執行引擎、本地方法接口和垃圾收集模塊

3)內存管理

①Java運行時涉及到的存儲區域主要包括程序計數器、Java虛擬機棧、本地方法棧、java堆、方法區以及直接內存等等

②對於每個部分,都有其使用的條件。程序計數器主要是取下一條指令,在Java裏面主要是取下一條指令的字節碼文件;Java虛擬機棧主要是利用棧先進後出的特性存儲局部變量表,動態鏈接等,主要包括堆內存和棧內存,對於程序員內存分析而言是特別重要的.Java堆是內存管理中最大的一塊,所有的線程共享這一塊內容,同時該部分也是垃圾收集器的主要區域。

③虛擬機的垃圾回收機制是完善的,動態內存分配和回收是比較成熟的,在內存管理機制中,大部分都不需要我們考慮內存回收,只有Java堆和方法區需要我們考慮處理內存問題。一般的對於內存回收首先就是判斷某一個部分是生存還是死亡,主要是通過下面二種算法:

其一是引用計數算法,本算法實現簡單,判定的效率也是比較高的,很多的軟件都使用了該算法,但是主流的Java並沒有選擇該算法,核心的問題是該算法難以處理對象之間相互調用的問題。

其二是稱可達性分析算法,該算法核心思想是依靠判斷對象是否存活來實現的,本算法是通過一系列的GC ROOTS的對象作爲起始點,採用搜索的算法遍歷引用鏈,如果搜索過程中沒有發現該節點,則認爲該節點是不可達的,即可回收的,在Java裏面,一般可以使用該算法處理問題。

 

註釋:

①引用計數算法:給對象中添加一個引用計數器,每當有一個地方引用它的時候,計數器就加1;當引用失效時,計數器值就減1;任何時刻計數器爲0的對象是不可能被使用的。 但是JVM並沒有使用引用計數來管理內存,其中最重要的原因就是它很難解決對象之間的相互引用關係。

引用計數算法的垃圾收集一般有侵入式與非侵入式兩種,侵入式的實現就是將引用計數器直接根植在對象內部,用C++的思想進行解釋就是,在對象的構造或者拷貝構造中進行加一操作,在對象的析構中進行減一操作,非侵入式恩想就是有一塊單獨的內存區域,用作引用計數器

引用其他作者的文章:https://www.cnblogs.com/WJ5888/p/4359783.html

②可達性分析算法:

在Java中採取了 可達性分析法。該方法的基本思想是通過一系列的“GC Roots”對象作爲起點進行搜索,如果在“GC Roots”和一個對象之間沒有可達路徑,則稱該對象是不可達的,不過要注意的是被判定爲不可達的對象不一定就會成爲可回收對象。被判定爲不可達的對象要成爲可回收對象必須至少經歷兩次標記過程,如果在這兩次標記過程中仍然沒有逃脫成爲可回收對象的可能性,則基本上就真的成爲可回收對象了。最後面兩句將object1和object2賦值爲null,也就是說object1和object2指向的對象已經不可能再被訪問,但是由於它們互相引用對方,導致它們的引用計數都不爲0,那麼垃圾收集器就永遠不會回收它們。

Java並不採用引用計數法來判斷對象是否已“死”,而採用“可達性分析”來判斷對象是否存活(同樣採用此法的還有C#、Lisp-最早的一門採用動態內存分配的語言)。 
此算法的核心思想:通過一系列稱爲“GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索走過的路徑稱爲“引用鏈”,當一個對象到 GC Roots 沒有任何的引用鏈相連時(從 GC Roots 到這個對象不可達)時,證明此對象不可用

對象Object5 —Object7之間雖然彼此還有聯繫,但是它們到 GC Roots 是不可達的,因此它們會被判定爲可回收對象。

在Java語言中,可作爲GC Roots的對象包含以下幾種:

  1. 虛擬機棧(棧幀中的本地變量表)中引用的對象。(可以理解爲:引用棧幀中的本地變量表的所有對象)
  2. 方法區中靜態屬性引用的對象(可以理解爲:引用方法區該靜態屬性的所有對象)
  3. 方法區中常量引用的對象(可以理解爲:引用方法區中常量的所有對象)
  4. 本地方法棧中(Native方法)引用的對象(可以理解爲:引用Native方法的所有對象)

可以理解爲:

(1)首先第一種是虛擬機棧中的引用的對象,我們在程序中正常創建一個對象,對象會在堆上開闢一塊空間,同時會將這塊空間的地址作爲引用保存到虛擬機棧中,如果對象生命週期結束了,那麼引用就會從虛擬機棧中出棧,因此如果在虛擬機棧中有引用,就說明這個對象還是有用的,這種情況是最常見的。

(2)第二種是我們在類中定義了全局的靜態的對象,也就是使用了static關鍵字,由於虛擬機棧是線程私有的,所以這種對象的引用會保存在共有的方法區中,顯然將方法區中的靜態引用作爲GC Roots是必須的。

(3)第三種便是常量引用,就是使用了static final關鍵字,由於這種引用初始化之後不會修改,所以方法區常量池裏的引用的對象也應該作爲GC Roots。最後一種是在使用JNI技術時,有時候單純的Java代碼並不能滿足我們的需求,我們可能需要在Java中調用C或C++的代碼,因此會使用native方法,JVM內存中專門有一塊本地方法棧,用來保存這些對象的引用,所以本地方法棧中引用的對象也會被作爲GC Roots。

4)特性

1.移植性 

無論是GC還是Hotspot都可以用在任何Java可用的地方。比方說,JRuby可以運行在其他平臺上,Rails應用就可以運行在IBM主機上的JRuby上,而且這臺IBM主機運行的是CP/CMS.實際上,由於Java和OpenJDK項目的開源,我們正在看到越來越多的平臺的衍生,因此JVM的移植性也將越來越棒。

2.成熟

JVM已有多年的歷史,在過去的這些年裏,許多開發者爲它做出了許多貢獻,使得它的性能一次又一次地提升,讓JVM變得更加穩定、快速和廣泛。

3.覆蓋面

Ruby和JVM上的其他語言項目已經被承認,一個例子是invokedynamic specification(akaJSR292)。JSR越來越配合新的語言,JVM已不再是Java一個人定製規則。JVM正在構建成爲類如JRuby等項目的優良平臺。還有一個MLVM(multiple languageVM)項目,好比是新特性的清算機構,是一個許多企業應用的開發者試圖添加應用的地方,而這些應用正是他們想在JVM中看到的。而且JVM開發者互相協作、彼此影響,無疑這有利於JVM新特性的誕生。這些細節都可以看到JVM正在關注開發者的需求,擴大他的覆蓋面

5)碎片回收

Java類的實例所需的存儲空間是在堆上分配的。解釋器具體承擔爲類實例分配空間的工作。解釋器在爲一個實例分配完存儲空間後,便開始記錄對該實例所佔用的內存區域的使用。一旦對象使用完畢,便將其回收到堆中。在Java語言中,除了new語句外沒有其他方法爲一對象申請和釋放內存。對內存進行釋放和回收的工作是由Java運行系統承擔的。這允許Java運行系統的設計者自己決定碎片回收的方法。在SUN公司開發的Java解釋器和Hot Java環境中,碎片回收用後臺線程的方式來執行。這不但爲運行系統提供了良好的性能,而且使程序設計人員擺脫了自己控制內存使用的風險。

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