十7、java內存模型_JVM_JDK_類加載

一、Java內存模型
  共享內存模型指的就是Java內存模型(簡稱JMM),JMM決定一個線程對共享變量的寫入時,能對另外一個線程可見。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(main memory)中,每一個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其餘的硬件和編譯器優化。
按照官方的說法:Java 虛擬機具備一個堆,堆是運行時數據區域,全部類實例和數組的內存均今後處分配。
 
從上圖來看,線程A與線程B之間如要通訊的話,必需要經歷下面2個步驟:
1)首先,線程A把本地內存A中更新過的共享變量刷新到主內存中去。
2)而後,線程B到主內存中去讀取線程A以前已更新過的共享變量。
下面經過示意圖來講明這兩個步驟:
 
如上圖所示,本地內存A和B有主內存中共享變量x的副本。假設初始時,這三個內存中的x值都爲0。線程A在執行時,把更新後的x值(假設值爲1)臨時存放在本身的本地內存A中。當線程A和線程B須要通訊時,線程A首先會把本身本地內存中修改後的x值刷新到主內存中,此時主內存中的x值變爲了1。隨後,線程B到主內存中去讀取線程A更新後的x值,此時線程B的本地內存的x值也變爲了1。
從總體來看,這兩個步驟實質上是線程A在向線程B發送消息,並且這個通訊過程必需要通過主內存。JMM經過控制主內存與每一個線程的本地內存之間的交互,來爲java程序員提供內存可見性保證。
總結:什麼是Java內存模型:java內存模型簡稱jmm,定義了一個線程對另外一個線程可見。共享變量存放在主內存中,每一個線程都有本身的本地內存,當多個線程同時訪問一個數據的時候,可能本地內存沒有及時刷新到主內存,因此就會發生線程安全問題。
二、Java內存模型包含的內容
Java內存模型定義了一種多線程訪問Java內存的規範。java內存模型的幾部份內容:
1)Java內存模型將內存分爲了 主內存和工做內存 。類的狀態,也就是類之間共享的變量,是存儲在主內存中的,每次Java線程用到這些主內存中的變量的時候,會讀一次主內存中的變量,並讓這些內存在本身的工做內存中有一份拷貝,運行本身線程代碼的時候,用到這些變量,操做的都是本身工做內存中的那一份。在線程代碼執行完畢以後,會將最新的值更新到主內存中去。
2)定義了幾個原子操做,用於操做主內存和工做內存中的變量。
3)定義了volatile變量的使用規則。
4)happens-before,即先行發生原則,定義了操做A必然先行發生於操做B的一些規則,好比在同一個線程內控制流前面的代碼必定先行發生於控制流後面的代碼、一個釋放鎖unlock的動做必定先行發生於後面對於同一個鎖進行鎖定lock的動做等等,只要符合這些規則,則不須要額外作同步措施,若是某段代碼不符合全部的happens-before規則,則這段代碼必定是線程非安全的。
三、JVM內存管理
JVM主要管理兩種內存:堆和非堆
1)堆內存(Heap Memory)是在 Java 虛擬機啓動時建立
  >堆是Java代碼可及的內存,留給開發人員使用的
  >存放java對象
2)非堆內存(Non-heap Memory)是在JVM堆以外的內存。
  >非堆是JVM留給本身用的,包含方法區、JVM內部處理或優化所需的內存(如 JITCompiler,Just-in-time Compiler,即時編譯後的代碼緩存)、每一個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法的代碼。
  >存放類加載信息和其它meta-data
3)其餘內存
  >存放JVM 自身代碼等
  在JVM啓動時,就已經保留了固定的內存空間給Heap內存,這部份內存並不必定都會被JVM使用,可是能夠肯定的是這部分保留的內存不會被其餘進程使用,這部份內存大小由-Xmx 參數指定。而另外一部份內存在JVM啓動時就分配給JVM,做爲JVM的初始Heap內存使用,這部份內存是由 -Xms 參數指定。
四、CAS 理解
  CAS,全稱爲Compare and Set,即比較-設置。假設有三個操做數: 內存值V、舊的預期值A、要修改的值B,當且僅當預期值A和內存值V相同時,纔會將內存值修改成B並返回true,不然什麼都不作並返回false 。固然CAS必定要volatile變量配合,這樣才能保證每次拿到的變量是主內存中最新的那個值,不然舊的預期值A對某條線程來講,永遠是一個不會變的值A,只要某次CAS操做失敗,永遠都不可能成功。
五、JRE與JVM、JDK的區別:
1)JVM就是咱們常說的java虛擬機,它是整個java實現跨平臺的 最核心的部分,全部的java程序會首先被編譯爲.class的類文件,這種類文件能夠在虛擬機上執行,也就是說class並不直接與機器的操做系統相對應,而是通過虛擬機間接與操做系統交互,由虛擬機將程序解釋給本地系統執行。JVM 的主要工做是解釋本身的指令集(即字節碼)到 CPU 的指令集或 OS 的系統調用,保護用戶免被惡意程序騷擾。JVM 對上層的 Java 源文件是不關心的,它關注的只是由源文件生成的類文件( class file )。類文件的 組成包括 JVM 指令集,符號表以及一些補助信息。
2)JRE java runtime environment
JRE是指java運行環境。光有JVM還不能成class的 執行,由於在解釋class的時候JVM須要調用解釋所須要的類庫lib。 在JDK的安裝目 錄裏你能夠找到jre目錄,裏面有兩個文件夾bin和lib,在 這裏能夠認爲bin裏的就是jvm,lib中則是jvm工做所須要的類庫,而jvm和 lib和起來就稱爲jre。因此,在你寫完java程序編譯成.class以後,你能夠把這個.class文件 和jre一塊兒打包發給朋友,這樣你的朋友就 能夠運行你寫程序了。(jre裏有運行.class的java.exe)JRE裏面有一個 JVM , JRE 與具體的 CPU 結構和操做系統有關,咱們從 Sun 下載 JRE 的時候就看到了不一樣的各類版本,同 JVM 一塊兒組成 JRE 的還有 一些 API (如 awt , swing 等), JRE 是 運行 Java 程序必不可少的.
3)JDK -- java development kit
JDK是java開發工具包,基本上每一個學java的人都會先在機器 上裝一個JDK,在JDK的安裝目錄下面 六個文件夾、一個src類庫源碼壓縮包、和其餘幾個聲明文件。其中,真正在運行java時起做用的 是如下四個文件夾:bin、include、lib、 jre。如今咱們能夠看出這樣一個關係,JDK包含JRE,而JRE包 含JVM。
bin:最主要的是編譯器(javac.exe)
include:java和JVM交互用的頭文件
lib:類庫
jre:java運行環境
(注意:這裏的bin、lib文件夾和jre裏的bin、lib是 不一樣的)總的來講JDK是用於java程序的開發,而jre則是隻能運行class而沒有編譯的功能。eclipse、idea等 其餘IDE有本身的編譯器而不是用JDK bin目錄中自帶的,因此在安裝時你會發現他們只要求你 選中jre路徑就ok了
三者之間的關係:Java 程序的字節碼文件能夠放到任意裝有 JRE 的計算機運行,再由不一樣 JRE 的將它們轉化成相應的機器代碼,這就實現了 Java 程序的可移植性。
六、JVM類加載原理
JVM在運行時會產生三個ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.
1)Bootstrap是用C++編寫的,咱們在Java中看不到它,是null,它用來加載核心類庫。
關於Bootstrap ClassLoader,在JVM源代碼中這樣寫道:
static const char classpathFormat[] =
"%/lib/rt.jar: "
"%/lib/i18n.jar: "
"%/lib/sunrsasign.jar: "
"%/lib/jsse.jar: "
"%/lib/jce.jar: "
"%/lib/charsets.jar: "
"%/classes ";
爲何不須要在classpath中加載這些類了?是由於在JVM啓動的時候就自動加載了,而且在運行過程當中根本不能修改Bootstrap加載路徑。
2)Extension ClassLoader用來加載擴展類,即/lib/ext中的類
3)AppClassLoader纔是加載Classpath的
ClassLoader加載類用的是委託模型。即先讓Parent類(而不是Super,不是繼承關係)尋找,Parent找不到才本身找。看來ClassLoader仍是蠻孝順的。三者的關係爲:AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent爲Bootstrap ClassLoader。加載一個類時,首先BootStrap先進行尋找,找不到再由ExtClassLoader尋找,最後纔是AppClassLoader。
爲何要設計的這麼複雜呢?其中一個重要緣由就是安全性。好比在Applet中,若是編寫了一個java.lang.String類並具備破壞性。假如不採用這種委託機制,就會將這個具備破壞性的String加載到了用戶機器上,致使破壞用戶安全。但採用這種委託機制則不會出現這種狀況。由於要加載java.lang.String類時,系統最終會由Bootstrap進行加載,這個具備破壞性的String永遠沒有機會加載。

java

相關文章
相關標籤/搜索