從廣義上講,Clojure、JRuby、Groovy等運行於Java虛擬機上的語言及其相關的程序都屬於Java技術體系中的一員。若是僅從傳統意義上來看,Sun官方所定義的Java技術體系包括如下幾個組成部分:html
咱們能夠把Java程序設計語言、Java虛擬機、Java API類庫這三部分統稱爲JDK(Java Development Kit),JDK是用於支持Java程序開發的最小環境。java
另外,能夠把Java API類庫中的Java SE API子集[1]和Java虛擬機這兩部分統稱爲JRE(Java Runtime Environment),JRE是支持Java程序運行的標準環境。web
以上是根據各個組成部分的功能來進行劃分的,若是按照技術所服務的領域來劃分,或者說按照Java技術關注的重點業務領域來劃分,Java技術體系能夠分爲4個平臺,分別爲:算法
Java Virtual Machine,Java虛擬機。是java編譯後的.class
文件(字節碼文件)與硬件系統之間的接口,也就是說用來運行.class
文件。JVM實現了Java最重要的特性:平臺無關性。spring
編譯後的 Java 程序指令並不直接在硬件系統的 CPU 上執行,而是由 JVM 執行,JVM屏蔽了與具體平臺相關的信息。JVM對字節碼文件進行解釋執行,把字節碼翻譯成相關平臺上的機器指令。
javac
是收錄於 JDK 中的 Java 語言編譯器。咱們使用javac
命令編譯Java源文件,獲得.class
文件。而後使用java
命令執行.class
文件(也就是使用JVM運行.class
文件)。使用jar
命令可對字節碼文件以及配置文件進行打包(可對一個由多個字節碼文件和配置文件等資源文件構成的項目進行打包)。小程序
因此不熟悉java的同窗要注意了,JVM並非用來編譯和執行java的,JVM只負責執行字節碼文件,編譯java文件由
javac
來完成
java有一套公用的規範:Java Language and Virtual Machine Specifications服務器
目前有三大Java虛擬機:HotSpot,oracle JRockit,IBM J9。架構
JRockit是oracle發明的,用於其WebLogic服務器,IBM JVM是IBM發明的用於其Websphere服務器,不一樣的JDK可能存在兼容性問題。oracle
JRockit和J9不存在永久代這種說法。這裏只討論HotSpot虛擬機,這也是目前使用的最多的JVM。Sun JDK7 HotSpot虛擬機的內存模型以下圖所示:spa
JVM的內存可分爲:線程棧、堆、靜態方法區,native方法使用的是直接內存,不包含在JVM中。Java NDK能夠調用C/C++。
方法區是可供各線程共享的運行時內存區域
方法區(Method Area)與Java堆同樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,可是它卻有一個別名叫作Non-Heap(非堆),目的應該是與Java堆區分開來。
在不一樣的JDK版本中,方法區中存儲的數據是不同的。在JDK1.6及以前,運行時常量池是方法區的一個部分,同時方法區裏面存儲了類的元數據信息、靜態變量、即時編譯器編譯後的代碼(好比spring 使用IOC或者AOP建立bean時,或者使用cglib,反射的形式動態生成class信息等)等。在JDK1.7及之後,JVM已經將運行時常量池從方法區中移了出來,在JVM堆開闢了一塊區域存放常量池。
方法區(method area)只是JVM規範中定義的一個概念,用於存儲類信息、常量池、靜態變量、JIT編譯後的代碼等數據,具體放在哪裏,不一樣的實現能夠放在不一樣的地方。
永久代是Hotspot虛擬機特有的概念,是方法區的一種實現,別的JVM都沒有這個東西。在Java 8中,永久代被完全移除,取而代之的是另外一塊與堆不相連的本地內存——元空間(Metaspace),‑XX:MaxPermSize 參數失去了意義,取而代之的是-XX:MaxMetaspaceSize。
永久代(PermGen)包含了JVM須要的應用元數據,這些元數據描述了在應用裏使用的類和方法。注意,永久代不是Java堆內存的一部分。永久代存放JVM運行時使用的類。永久代一樣包含了Java SE庫的類和方法。永久代的對象在full GC時進行垃圾收集。
對於習慣在HotSpot虛擬機上開發、部署程序的開發者來講,不少人都更願意把方法區稱爲「永久代」(Permanent Generation),本質上二者並不等價,僅僅是由於HotSpot虛擬機的設計團隊選擇把GC分代收集擴展至方法區,或者說使用永久代來實現方法區而已,這樣HotSpot的垃圾收集器能夠像管理Java堆同樣管理這部份內存,可以省去專門爲方法區編寫內存管理代碼的工做。對於其餘虛擬機(如BEA JRockit、IBM J9等)來講是不存在永久代的概念的。原則上,如何實現方法區屬於虛擬機實現細節,不受虛擬機規範約束,不一樣的JVM廠商,針對本身的JVM可能有不一樣的方法區實現方式。但使用永久代來實現方法區,如今看來並非一個好主意,由於這樣更容易遇到內存溢出問題(永久代有-XX:MaxPermSize的上限,J9和JRockit只要沒有觸碰到進程可用內存的上限,例如32位系統中的4GB,就不會出現問題),並且有極少數方法(例如String.intern())會因這個緣由致使不一樣虛擬機下有不一樣的表現。所以,對於HotSpot虛擬機,根據官方發佈的路線圖信息,如今也有放棄永久代並逐步改成採用Native Memory來實現方法區的規劃了,在目前已經發布的JDK 1.7的HotSpot中,已經把本來放在永久代的字符串常量池移出。
也就是說永久代是JVM規範中方法區的一種實現方式
Java虛擬機規範對方法區的限制很是寬鬆,除了和Java堆同樣不須要連續的內存和能夠選擇固定大小或者可擴展外,還能夠選擇不實現垃圾收集。相對而言,垃圾收集行爲在這個區域是比較少出現的,但並不是數據進入了方法區就如永久代的名字同樣「永久」存在了。這區域的內存回收目標主要是針對常量池的回收和對類型的卸載,通常來講,這個區域的回收「成績」比較難以使人滿意,尤爲是類型的卸載,條件至關苛刻,可是這部分區域的回收確實是必要的。在Sun公司的BUG列表中,曾出現過的若干個嚴重的BUG就是因爲低版本的HotSpot虛擬機對此區域未徹底回收而致使內存泄漏。
根據Java虛擬機規範的規定,當方法區沒法知足內存分配需求時,將拋出OutOfMemoryError異常。
Eden
(伊甸園)和兩個Survivor
區域,這兩個Survivor
區域分別被命名爲from
和to
以示區分。默認狀況下,它們的空間大小關係是Eden:from:to=8:1:1
。下面要講的GC(garbage collection)就是針對堆
進行內存回收。
-Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -Xss1M
Xms是JVM初始堆的大小,Xmx是JVM最大堆大小,Xmn是新生代大小,PermSize是永久代的初始大小,MaxPermSize是永久代的最大大小,Xss是每一個線程棧的大小。JVM系列三:JVM參數設置、分析
虛擬機初始化時已經設定了各部分的內存大小,分爲三部分:
新生代採用複製算法。將新生代分爲3個區:較大的Eden和兩個較小的Survivor。發生在新生代的GC爲Minor GC,在Minor GC時會將新生代中還存活着的對象複製進一個Survivor中,而後對Eden和另外一個Survivor進行清理。因此日常可用的新生代大小爲Eden大小+一個Survivor大小。