雖是讀書筆記,可是如轉載請註明出處https://uestc-dpz.github.io
..拒絕伸手複製黨html
Java 虛擬機 Java 虛擬機(Java virtual machine,JVM)是運行 Java 程序必不可少的機制。JVM實現了Java語言最重要的特徵:即平臺無關性。原理:編譯後的 Java 程序指令並不直接在硬件系統的 CPU 上執行,而是由 JVM 執行。JVM屏蔽了與具體平臺相關的信息,使Java語言編譯程序只須要生成在JVM上運行的目標字節碼(.class),就能夠在多種平臺上不加修改地運行。Java 虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。所以實現java平臺無關性。它是 Java 程序能在多平臺間進行無縫移植的可靠保證,同時也是 Java 程序的安全檢驗引擎(還進行安全檢查)。 java
JVM 是 編譯後的 Java 程序(.class文件)和硬件系統之間的接口 ( 編譯後:javac 是收錄於 JDK 中的 Java 語言編譯器。該工具能夠將後綴名爲. java 的源文件編譯爲後綴名爲. class 的能夠運行於 Java 虛擬機的字節碼。)git
JVM architecture:
圖片摘自 http://javapapers.com/java/ja...程序員
JVM = 類加載器 classloader + 執行引擎 execution engine + 運行時數據區域 runtime data area
classloader 把硬盤上的class 文件加載到JVM中的運行時數據區域, 可是它不負責這個類文件可否執行,而這個是 執行引擎 負責的。github
做用:裝載.class文件
classloader 有兩種裝載class的方式 (時機):算法
隱式:運行過程當中,碰到new方式生成對象時,隱式調用classLoader到JVMbootstrap
顯式:經過class.forname()動態加載數組
雙親委派模型(Parent Delegation Model):緩存
類的加載過程採用雙親委託機制,這種機制能更好的保證 Java 平臺的安全。
該模型要求除了頂層的Bootstrap class loader啓動類加載器外,其他的類加載器都應當有本身的父類加載器
。子類加載器和父類加載器不是以繼承(Inheritance)的關係
來實現,而是經過組合(Composition)關係
來複用父加載器的代碼。每一個類加載器都有本身的命名空間(由該加載器及全部父類加載器所加載的類組成,在同一個命名空間中,不會出現類的完整名字(包括類的包名)相同的兩個類;在不一樣的命名空間中,有可能會出現類的完整名字(包括類的包名)相同的兩個類)安全
雙親委派模型的工做過程爲:
1.當前 ClassLoader 首先從本身已經加載的類中查詢是否此類已經加載,若是已經加載則直接返回原來已經加載的類。
每一個類加載器都有本身的加載緩存,當一個類被加載了之後就會放入緩存, 等下次加載的時候就能夠直接返回了。
2.當前 classLoader 的緩存中沒有找到被加載的類的時候,委託父類加載器去加載,父類加載器採用一樣的策略,首先查看本身的緩存,而後委託父類的父類去加載,一直到 bootstrap ClassLoader.
當全部的父類加載器都沒有加載的時候,再由當前的類加載器加載,並將其放入它本身的緩存中,以便下次有加載請求的時候直接返回。
使用這種模型來組織類加載器之間的關係的好處:
主要是爲了安全性
,避免用戶本身編寫的類動態替換 Java 的一些核心類,好比 String,同時也避免了重複加載
,由於 JVM 中區分不一樣類,不只僅是根據類名,相同的 class 文件被不一樣的 ClassLoader 加載就是不一樣的兩個類,若是相互轉型的話會拋java.lang.ClassCaseException.
類加載器 classloader 是具備層次結構的,也就是父子關係。其中,Bootstrap 是全部類加載器的父親。以下圖所示:
Bootstrap class loader: 父類
當運行 java 虛擬機時,這個類加載器被建立,它負責加載虛擬機的核心類庫,如 java.lang.* 等。例如 java.lang.Object 就是由根類加載器加載的。須要注意的是,這個類加載器不是用 java 語言寫的,而是用 C/C++ 寫的。
Extension class loader:
這個加載器加載出了基本 API 以外的一些拓展類。
AppClass Loader:
加載應用程序和程序員自定義的類。
除了以上虛擬機自帶的加載器之外,用戶還能夠定製本身的類加載器(User-defined Class Loader)。Java 提供了抽象類 java.lang.ClassLoader,全部用戶自定義的類加載器應該繼承 ClassLoader 類。
這是JVM分工自治生態系統的一個很好的體現。
http://www.importnew.com/6581...
做用: 執行字節碼,或者執行本地方法
JVM 運行時數據區 (JVM Runtime Area) 其實就是指 JVM 在運行期間,其對JVM內存空間的劃分和分配。JVM在運行時將數據劃分爲了6個區域來存儲。
程序員寫的全部程序都被加載到運行時數據區域
中,不一樣類別存放在heap, java stack, native method stack, PC register, method area.
下面對各個部分的功能和存儲的內容進行描述:
一、PC程序計數器:一塊較小的內存空間,能夠看作是當前線程
所執行的字節碼的行號指示器, NAMELY存儲每一個線程下一步將執行的JVM指令,如該方法爲native的,則PC寄存器中不存儲任何信息。Java 的多線程機制離不開程序計數器,每一個線程都有一個本身的PC,以便完成不一樣線程上下文環境的切換。
二、java虛擬機棧:與 PC 同樣,java 虛擬機棧也是線程私有的。每個 JVM 線程都有本身的 java 虛擬機棧,這個棧與線程同時建立,它的生命週期與線程相同。虛擬機棧描述的是Java 方法執行的內存模型
:每一個方法被執行的時候都會同時建立一個棧幀(Stack Frame)
用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個方法被調用直至執行完成的過程就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程
。
三、本地方法棧:與虛擬機棧的做用類似,虛擬機棧爲虛擬機執行執行java方法服務,而本地方法棧則爲虛擬機使用到的本地方法服務。
四、Java堆:被全部線程共享的一塊存儲區域,在虛擬機啓動時建立,它是JVM用來存儲對象實例以及數組值的區域,能夠認爲Java中全部經過new建立的對象的內存都在此分配。
Java堆在JVM啓動的時候就被建立,堆中儲存了各類對象,這些對象被自動管理內存系統(Automatic Storage Management System,也便是常說的 「Garbage Collector(垃圾回收器)」)所管理。這些對象無需、也沒法顯示地被銷燬。
JVM將Heap分爲兩塊:新生代New Generation和舊生代Old Generation
Note:
堆在JVM是全部線程共享的,所以在其上進行對象內存的分配均須要進行加鎖,這也是new開銷比較大的緣由。
鑑於上面的緣由,Sun Hotspot JVM爲了提高對象內存分配的效率,對於所建立的線程都會分配一塊獨立的空間,這塊空間又稱爲TLAB
TLAB僅做用於新生代的Eden Space,所以在編寫Java程序時,一般多個小的對象比大的對象分配起來更加高效
五、方法區
方法區和堆區域同樣,是各個線程共享的內存區域,它用於存儲每個類的結構信息
,例如運行時常量池,成員變量和方法數據,構造函數和普通函數的字節碼內容,還包括一些在類、實例、接口初始化時用到的特殊方法。當開發人員在程序中經過Class對象中的getName、isInstance等方法獲取信息時,這些數據都來自方法區。
方法區也是全局共享的,在虛擬機啓動時候建立。在必定條件下它也會被GC。這塊區域對應Permanent Generation 持久代。 XX:PermSize指定大小。
六、運行時常量池
其空間從方法區中分配,存放的爲類中固定的常量信息、方法和域的引用信息。
Java garbage collection is an automatic process to manage the runtime memory used by programs. By doing it automatic JVM relieves the programmer of the overhead of assigning and freeing up memory resources in a program.
java 與 C語言相比的一個優點是,能夠經過本身的JVM自動分配和回收內存空間。
何爲GC?
垃圾回收機制是由垃圾收集器Garbage Collection GC來實現的,GC是後臺的守護進程。它的特別之處是它是一個低優先級進程,可是能夠根據內存的使用狀況動態的調整他的優先級。所以,它是在內存中低到必定限度時纔會自動運行,從而實現對內存的回收。這就是垃圾回收的時間不肯定的緣由。
爲什麼要這樣設計:由於GC也是進程,也要消耗CPU等資源,若是GC執行過於頻繁會對java的程序的執行產生較大的影響(java解釋器原本就不快),所以JVM的設計者們選着了不按期的gc。
GC有關的是: runtime data area 中的 heap(對象實例會存儲在這裏) 和 gabage collector方法。
程序運行期間,全部對象實例存儲在運行時數據區域的heap中,當一個對象再也不被引用(使用),它就須要被收回。在GC過程當中,這些再也不被使用的對象從heap中收回,這樣就會有空間被循環利用。
GC爲內存中再也不使用的對象進行回收,GC中調用回收的方法
--收集器garbage collector
. 因爲GC要消耗一些資源和時間,Java 在對對象的生命週期特徵(eden or survivor)進行分析以後,採用了分代
的方式進行對象的收集,以縮短GC對應用形成的暫停。
在垃圾回收器回收內存以前,還須要一些清理工做。
由於垃圾回收gc只能回收經過new關鍵字申請的內存(在堆上),可是堆上的內存並不徹底是經過new申請分配的。還有一些本地方法(通常是調用的C方法)。這部分「特殊的內存」若是不手動釋放,就會致使內存泄露,gc是沒法回收這部份內存的。
因此須要在finalize中用本地方法(native method)如free操做等,再使用gc方法。顯示的GC方法是system.gc()
方法一:引用計數法。簡單但速度很慢。缺陷是:不能處理循環引用的狀況。
方法二:中止-複製(stop and copy)。效率低,須要的空間大,優勢,不會產生碎片。
方法三:標記 - 清除算法 (mark and sweep)。速度較快,佔用空間少,標記清除後會產生大量的碎片。
JAVA虛擬機中是如何作的?
java的作法很聰明,咱們稱之爲"自適應"的垃圾回收器,或者是"自適應的、分代的、中止-複製、標記-清掃"式垃圾回收器。它會根據不一樣的環境和須要選擇不一樣的處理方式。
因爲GC須要消耗一些資源和時間的,Java在對對象的生命週期特徵進行分析後,採用了分代
的方式來進行對象的收集,即按照新生代、舊生代的方式來對對象進行收集,以儘量的縮短GC對應用形成的暫停.
heap 的組成有三區域/世代:(能夠理解隨着時間,對象實例不斷變換heap中的等級,有點像年級)
新生代 Young Generation
Eden Space 任何新進入運行時數據區域的實例都會存放在此
S0 Suvivor Space 存在時間較長,通過垃圾回收沒有被清除的實例,就從Eden 搬到了S0
S1 Survivor Space 同理,存在時間更長的實例,就從S0 搬到了S1
舊生代 Old Generation/tenured
同理,存在時間更長的實例,對象屢次回收沒被清除,就從S1 搬到了tenured
Perm 存放運行時數據區的方法區
Java 不一樣的世代使用不一樣的 GC 算法。
Minor collection:
新生代 Young Generation 使用將 Eden 還有 Survivor 內的數據利用 semi-space 作複製收集(Copying collection), 並將本來 Survivor 內通過屢次垃圾收集仍然存活的對象移動到 Tenured。
Major collection 則會進行 Minor collection,Tenured 世代則進行標記壓縮收集。
To note that:
這個搬運工做都是GC 完成的,這也是garbage collector 的名字來源,而不是叫garbage cleaner. GC負責在heap中搬運實例,以及收回存儲空間。
JVM 分別對新生代和舊生代採用不一樣的垃圾回收機制
Java中那些不可達的對象
就會變成垃圾
。那麼什麼叫作不可達?其實就是沒有辦法再引用
到該對象了。主要有如下狀況使對象變爲垃圾:
1.對非線程的對象
來講,全部的活動線程都不能訪問該對象,那麼該對象就會變爲垃圾。
2.對線程對象來講,知足上面的條件,且線程未啓動或者已中止。
例如: (1)改變對象的引用,如置爲null或者指向其餘對象。 Object x=new Object();//object1 Object y=new Object();//object2 x=y;//object1 變爲垃圾 x=y=null;//object2 變爲垃圾 (2)超出做用域 if(i==0){ Object x=new Object();//object1 }//括號結束後object1將沒法被引用,變爲垃圾 (3)類嵌套致使未徹底釋放 class A{ A a; } A x= new A();//分配一個空間 x.a= new A();//又分配了一個空間 x=null;//將會產生兩個垃圾 (4)線程中的垃圾 class A implements Runnable{ void run(){ //.... } } //main A x=new A();//object1 x.start(); x=null;//等線程執行完後object1才被認定爲垃圾 這樣看,確實在代碼執行過程當中會產生不少垃圾,不過不用擔憂,java能夠有效地處理他們。
JVM中將對象的引用分爲了四種類型,不一樣的對象引用類型會形成GC採用不一樣的方法進行回收:
(1)強引用:默認狀況下,對象採用的均爲強引用
(GC不會回收)
(2)軟引用:軟引用是Java中提供的一種比較適合於緩存場景的應用
(只有在內存不夠用的狀況下才會被GC)
(3)弱引用:在GC時必定會被GC回收
(4)虛引用:在GC時必定會被GC回收
想更一進步的支持我,請掃描下方的二維碼,你懂的~