類加載子系統
:加載的類信息存放於方法區
當中,方法區
當中可能還包括運行時常量池信息,包括字符串字面量和數字常量。Java堆
:堆在虛擬機啓動的時候創建,它是Java程序最主要的內存工做區域,幾乎全部的Java對象實例都存放在Java堆當中,堆空間是全部線程共享的,這是一塊與Java應用密切相關的內存空間。Java棧
:是每個線程所私有的內存空間,Java
棧是線程執行密切相關的,線程執行的基本行爲是函數間的調用,每次函數調用的數據都是Java棧傳遞的。不管是JVM仍是計算機的操做系統,在函數調用時都須要用到棧,在Intellij idea的Debug界面中,咱們就能夠看到棧信息:其中的一項,稱爲一個棧幀
,一個棧幀中,至少包含局部變量表、操做數棧、幀數據區幾個部分。當一個函數返回時,棧幀會被從Java棧中彈出。(返回包括return和異常)html
本地方法棧
:本地指的是Native
,JVM容許Java直接調用本地方法。PC
:Program Counter,即程序計數器
,和CPU裏面的PC表示的是一個意思,即Java代碼當前走到的位置。一個Java線程是在執行一個方法,這個正在執行的方法稱爲當前方法,若是當前方法不是本地方法,那麼就指向正在執行的指令
,若是執行的是本地方法,那麼PC寄存器的值就是undefined。執行引擎
:是java虛擬機的最核心組件之一,它負責執行虛擬機的字節碼,現代虛擬機爲了提升執行效率,會使用即時編譯技術將方法編譯成機器碼後再執行。其實,咱們能夠發現,灰色的區域(Java棧、本地方法棧、程序計數器)是線程私有的,而其餘的空間則是線程共用的。java
這三者都是線程私有的。算法
PC寄存器
用來存儲指向下一條指令的地址,也即將要執行的指令代碼,由執行引擎讀取下一條的指令。它是一塊很小的內存空間,幾乎能夠忽略不計,也是運行速度最快的存儲區域。在JVM規範中每一個線程都有本身的程序計數器,是線程私有的,生命週期同線程週期保持一致。緩存
PC寄存器是程序控制流的指示器,分支、循環、跳轉、異常處理、線程恢復等等最基礎的工做都要依賴它完成。markdown
它是惟一一個在Java虛擬機規範中,沒有規定任何OOM狀況的區域。也沒有GC的區域。ide
每一次函數的調用,都會在調用棧上維護一個獨立的棧幀,棧幀通常包括:函數
局部變量表:是一組變量值的存儲空間,用來存放方法參數和局部變量,虛擬機經過索引定位的方式使用局部變量表。儲存包括八種基本數據類型
、對象的引用地址
,參與方法的調用和返回。工具
操做數棧:存放方法調用時的實參,即操做數(在概念模型中各個棧幀都是相互獨立的,可是實際實現時,都會使兩個獨立的棧幀一部分重疊,下面的部分操做數棧與上面的局部變量表重疊在一塊區域,這樣在方法調用時能夠共用一部分的數據。)。oop
動態連接:(略,其實就是指向運行時常量池的方法引用)。性能
方法返回地址:方法的返回分紅兩個狀況:
不管是異常仍是正常,退出方法的時候,都會退出到最開始的調用處。
- 若是是正常退出,那麼調用者的PC 寄存器便可做爲返回地址。
- 若是是異常退出,那麼就參照異常處理表來肯定。
本地方法本質上時依賴於實現的,虛擬機實現的設計者們能夠自由地決定使用怎樣的機制來讓Java程序調用本地方法。
一個JVM只存在一個堆內存
,堆是Java內存管理的核心區域。它在JVM虛擬機建立時即被建立,大小就已經肯定了,是JVM所管理的最大的一塊內存空間。堆在物理上不要求其連續,可是在邏輯上要求是連續的。全部的線程共享Java堆,能夠在堆中劃分線程私有的緩衝區
。
區分爲 : 新生代 + 老年代 + 永久代
區分爲:新生代 + 老年代 + 元空間
1.內存劃分和JVM的一項重要的功能:GC(垃圾回收)有很是大的關係,不一樣的對象,不一樣區的對象GC回收的頻率不一樣,主要參照GC算法。
2. 咱們建立的對象(至關多的一部分都是臨時對象),存放在新生代,使用相對短的時間便可被回收的,若是沒有被回收的就說明,這個對象的使用頻率相對來講高,屢次GC都不能回收。而永久代則用於存儲class、運行時常量池、字段、方法、代碼、JIT代碼等。
3. 永久代和方法區是什麼關係? 永久代是方法區的一種實現,咱們規定類加載後生成的Class對象放在方法區當中,這是JVM的規範的一部分,可是並無說:必須開闢一個內存,名稱爲方法區。實際上咱們選擇在永久代中構建方法區,來存儲這些對象。也不是全部虛擬機都有永久代的,咱們使用的HotSpot的JVM中的虛擬機只存在於JDK7以前,JDK8及以後被MetaSpace(元空間)所替代了。
4. GC算法和堆內存的劃分是什麼關係? GC算法主要是根據一些列的規則判斷該對象是否還有存活的價值,及時釋放無關對象能夠節省空間。而堆內存的劃分則和GC的頻率有關係,各自劃份內的GC算法也不相同。
- 新生代:GC的頻率相對較高。
- 老年代:GC的頻率相對較低。
- 永久代:主要是GC一些卸載的類和廢棄的常量。
字節碼讀入JVM後,機器並不能讀懂字節碼,只有JVM自身能讀懂它,因此JVM必須作一件事情,將JVM翻譯成相關平臺的機器碼(01),具體的過程在這章不作展開。這裏講講在Android中使用的JIT技術和AOT技術,前者是動態編譯,然後者是靜態編譯。
早期的Android(Android 2.1及以前)應用程序執行Java代碼其實是解釋器將每一個Java指令 翻譯成 等價的幾條微處理器指令,而且,根據轉譯後的指令一條一條地按照次序進行執行。這樣的執行方式須要在執行前進行翻譯,運行是可想而知的低效。
Android2.2 以後 引入了JIT技術,該技術簡單來講就是:每遇到一個Class文件,JIT就會對這個類進行編譯,生成至關精簡的二進制碼,花費少量的編譯時間來換取後續執行的速率。JIT的提出對性能提高是比較大的,可是確實十分有限的。由於某些Java文件是極少執行的,編譯他們的時間有可能遠遠長於翻譯器翻譯他們的時間。總體下來,花費的時間並無減小。
後來,基於JIT的經驗,又提出了動態編譯器,動態地預判那些須要編譯,哪些須要翻譯,因此動態編譯器是既包含了編譯器、又包含了解釋器的。
Java文件進行編譯後,都是字節碼文件(ByteCode),不管是傳統的JVM,或者是Dalvik、ART虛擬機,只是各類虛擬機下的ByteCode的組成方式有所差別。其中,JVM對應的運行文件是.Class文件,而Dalvik對應的則是.dex文件,DVM專門對移動操做系統的特性進行了優化,而且基於寄存器進行設計。指令集具備很大的不一樣。(基於寄存器進行設計的內容可參考RISC:即精簡指令系統計算機,指令精簡且關鍵,更多地依賴寄存器來獲取更快的速度和更低的功耗)
Ahead-Of-Time技術。
ART模式(Android runtime)做爲一個可選功能在Android 4.4的開發者選項中首次出現,做爲Davlik的備選項,ART在安裝時就會進行編譯動做,編譯的文件也再也不是一個字節碼,而是具體的可執行文件,能夠運行在更爲底層的硬件上,這樣在運行時,就省下了預編譯和翻譯的時間。該可執行文件本質上是一個ELF文件(是一種用於二進制文件、可執行文件、目標代碼、共享庫、核心轉儲格式文件),在Android中,咱們沒法找到顯式存在的OAT文件,其實OAT文件仍然是以.odex做爲後綴的,經過file命令或者UE打開能夠看到ELF頭部。
ART設計是考慮兼容性的,即便是早期編譯的Android Project中的Dex文件也能夠在運行ART模式的Android設備上使用。這是經過dex2oat作到的,dalvik下的dex、odex文件都可以經過這個工具轉化爲oat文件,而且odex文件將比dex文件編譯的更快。
Odex文件即Optimize Dex,對dex文件的優化,最直觀的好處:decodex在系統第一次開機時,須要提取全部APK中的Dex文件,而Odex優化是提早提取出來了,這樣運行速度和開機速度都有提升。其次Odex優化後,APK中能夠沒有Dex文件,而爲Odex在Apk包中有一份Dex文件,在/data/dalvik-cache下還有提取出來的一份,浪費存儲空間。必定程度上保護了硬件廠商本身的APK,由於APK中只有資源文件,反彙編並無意義。具體的代碼都在Odex之中了。
也正是由於AOT技術,在搭載Android 5.0系統的機器上,初始化後或者是初次開機啓動很是的慢,由於系統會提取全部App的dex字節碼,優化而且拷貝到/data/dalvik-cache緩存目錄中,所以,第一次啓動耗時會明顯更高。
在Android 7.0 中,JIT被從新啓用,採用AOT/JIT 混合編譯的策略,特色是: