<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    大漠駝鈴

    置身浩瀚的沙漠,方向最為重要,希望此blog能向大漠駝鈴一樣,給我方向和指引。
    Java,Php,Shell,Python,服務器運維,大數據,SEO, 網站開發、運維,云服務技術支持,IM服務供應商, FreeSwitch搭建,技術支持等. 技術討論QQ群:428622099
    隨筆 - 238, 文章 - 3, 評論 - 117, 引用 - 0
    數據加載中……

    JVM學習之-JVM內存結構



    1.1     JVM運行

    ClassLoader->RUNNTIME DATA AREA->EXECUTION ENGINE->NATIVE INTERFACE->NATIVE LIBRARIES

    Class Loader:負責加載類到內存

    RUNNTIME DATA AREA:負責

    EXECUTION ENGINE:  解釋器Interpreter,負責解釋命令,提交到操作系統

    NATIVE INTERFACE: NATIVE METHOD STATCK中登記NATIVE方法,在Executive Engine執行時加載native libraies.

     

     CLassLoader

    類加載器的作用是加載類文件到內存,比如編寫一個HelloWord.java程序,然后通過javac編譯成class文件,那怎么才能加載到內存中被執行呢?Class Loader承擔的就是這個責任,那不可能隨便建立一個.class文件就能被加載的,Class Loader加載的class文件是有格式要求,在《JVM Specification》中式這樣定義Class文件的結構:

    ClassFile {

     u4 magic;

    u2 minor_version;

    u2 major_version;

    u2 constant_pool_count;

    cp_info constant_pool[constant_pool_count-1];

    u2 access_flags;

    u2 this_class;

    u2 super_class;

    u2 interfaces_count;

    u2 interfaces[interfaces_count];

    u2 fields_count;

    field_info fields[fields_count];

    u2 methods_count;

    method_info methods[methods_count];

    u2 attributes_count;

    attribute_info attributes[attributes_count];

    }

    需要詳細了解的話,可以仔細閱讀《JVM Specification》的第四章“The class File Format”,這里不再詳細說明。

    友情提示:Class Loader只管加載,只要符合文件結構就加載,至于說能不能運行,則不是它負責的,那是由Execution Engine負責的。

    Execution Engine 執行引擎

    執行引擎也叫做解釋器(Interpreter),負責解釋命令,提交操作系統執行。

    Native Interface本地接口

    本地接口的作用是融合不同的編程語言為Java所用,它的初衷是融合C/C++程序,Java誕生的時候是C/C++橫行的時候,要想立足,必須有一個聰明的、睿智的調用C/C++程序,于是就在內存中專門開辟了一塊區域處理標記為native的代碼,它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時加載native libraies。目前該方法使用的是越來越少了,除非是與硬件有關的應用,比如通過Java程序驅動打印機,或者Java系統管理生產設備,在企業級應用中已經比較少見,因為現在的異構領域間的通信很發達,比如可以使用Socket通信,也可以使用Web Service等等,不多做介紹。

     

    NATIVE METHOD STATCK中登記NATIVE方法,在Executive Engine執行時加載native libraies.

    1.2     RUNTIME AREA

    運行數據區是整個JVM的重點。我們所有寫的程序都被加載到這里,之后才開始運行,Java生態系統如此的繁榮,得益于該區域的優良自治。

     

     

    PROGEAM COUNTER REGISTER

    線程私有、指向下一條要很執行的指令

    JAVA STACK

    線程私有、存儲局部變量表、操作棧、動態鏈接、方法出口

    NATIVE METHOD STACK

    為虛擬機使用到的Native 方法服務

    HEAP

    線程共享

    所有的對象實例以及數組都要在堆上分配

    回收器主要管理的對象

     

    MEATHOD AREA

    線程共享的內存區域

    非堆主要區域

    存儲類信息、常量、靜態變量、即時編譯器編譯后的代碼

     

    1.2.1     程序計數器

    程序計數器(Program Counter Register)是一塊較小的內存空間,它的作用可以看做是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型里(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現),字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

     

    由于Java 虛擬機的多線程是通過線程輪流切換并分配處理器執行時間的方式來實現

    的,在任何一個確定的時刻,一個處理器(對于多核處理器來說是一個內核)只會執行

    一條線程中的指令。因此,為了線程切換后能恢復到正確的執行位置,每條線程都需要

    有一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲,我們稱這類內

    存區域為“線程私有”的內存。

     

    如果線程正在執行的是一個Java 方法,這個計數器記錄的是正在執行的虛擬機字節

    碼指令的地址;如果正在執行的是Natvie 方法,這個計數器值則為空(Undefined)。此

    內存區域是唯一一個在Java 虛擬機規范中沒有規定任何OutOfMemoryError 情況的區域。

     

    1.2.2    

    與程序計數器一樣,Java 虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,

    它的生命周期與線程相同。虛擬機棧描述的是Java 方法執行的內存模型:每個方法被執

    行的時候都會同時創建一個棧幀(Stack Frame①)用于存儲局部變量表、操作棧、動態鏈接、方法出口等信息。

    每一個方法被調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。

     經常有人把Java 內存區分為堆內存(Heap)和棧內存(Stack),這種分法比較粗

    糙,Java 內存區域的劃分實際上遠比這復雜。這種劃分方式的流行只能說明大多數程序

    員最關注的、與對象內存分配關系最密切的內存區域是這兩塊。

     

    其中所指的“堆”在后面會專門講述,而所指的“棧”就是現在講的虛擬機棧,或者說是虛擬機棧中的局部變量表部分。

     

    局部變量表存放了編譯期可知的各種基本數據類型(booleanbytecharshortint

    floatlongdouble)、對象引用(reference 類型,它

    不等同于對象本身,根據不同的虛擬機實現,它可能是一個指向對象起始地址的引用指針,也可能指向一個代表對象的句柄或者其他與此對象相關的位置)和returnAddress 類型(指向了一條字節碼指令的地址)。

    其中64 位長度的long double 類型的數據會占用2 個局部變量空間(Slot),其余

    的數據類型只占用1 個。

    局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。

     

    Java 虛擬機規范中,對這個區域規定了兩種異常狀況:如果線程請求的棧深度大

    于虛擬機所允許的深度,將拋出StackOverflowError 異常;如果虛擬機棧可以動態擴展

    (當前大部分的Java 虛擬機都可動態擴展,只不過Java 虛擬機規范中也允許固定長度的

    虛擬機棧),當擴展時無法申請到足夠的內存時會拋出OutOfMemoryError 異常。

     

    1.2.3     本地方法棧

    本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其

    區別不過是虛擬機棧為虛擬機執行Java 方法(也就是字節碼)服務,而本地方法棧則

    是為虛擬機使用到的Native 方法服務。虛擬機規范中對本地方法棧中的方法使用的語

    言、使用方式與數據結構并沒有強制規定,因此具體的虛擬機可以自由實現它。甚至

    有的虛擬機(譬如Sun HotSpot 虛擬機)直接就把本地方法棧和虛擬機棧合二為一。

    與虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError OutOfMemoryError

    異常。

     

    1.2.4     Java

    對于大多數應用來說,Java 堆(Java Heap)是Java 虛擬機所管理的內存中最大的

    一塊。

    Java 堆是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的

    唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。這一點在Java

    擬機規范中的描述是:所有的對象實例以及數組都要在堆上分配,但是隨著JIT 編譯器

    的發展與逃逸分析技術的逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙

    的變化發生,所有的對象都分配在堆上也漸漸變得不是那么“絕對”了。

     

    Java 堆是垃圾收集器管理的主要區域,因此很多時候也被稱做“GC 堆”(Garbage

    Collected Heap,幸好國內沒翻譯成“垃圾堆”)。如果從內存回收的角度看,由于現在

    收集器基本都是采用的分代收集算法,所以Java 堆中還可以細分為:新生代和老年代;

    再細致一點的有Eden 空間、From Survivor 空間、To Survivor 空間等。

    如果從內存分配的角度看,線程共享的Java 堆中可能劃分出多個線程私有的分配緩沖區(Thread LocalAllocation BufferTLAB)。不過,無論如何劃分,都與存放內容無關,無論哪個區域,存儲的都仍然是對象實例,進一步劃分的目的是為了更好地回收內存,或者更快地分配內存。

     

    根據Java 虛擬機規范的規定,Java 堆可以處于物理上不連續的內存空間中,只要

    邏輯上是連續的即可,就像我們的磁盤空間一樣。在實現時,既可以實現成固定大小

    的,也可以是可擴展的,不過當前主流的虛擬機都是按照可擴展來實現的(通過-Xmx

    -Xms 控制)。如果在堆中沒有內存完成實例分配,并且堆也無法再擴展時,將會拋出

    OutOfMemoryError 異常。

     

    1.2.5     方法區

    方法區(Method Area)與Java 堆一樣,是各個線程共享的內存區域,它用于存

    儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。雖

    Java 虛擬機規范把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做Non-

    Heap(非堆),目的應該是與Java 堆區分開來。

     

    對于習慣在HotSpot 虛擬機上開發和部署程序的開發者來說,很多人愿意把方法區

    稱為“永久代”(Permanent Generation),本質上兩者并不等價,僅僅是因為HotSpot

    擬機的設計團隊選擇把GC 分代收集擴展至方法區,或者說使用永久代來實現方法區而

    已。對于其他虛擬機(如BEA JRockitIBM J9 等)來說是不存在永久代的概念的。即

    使是HotSpot 虛擬機本身,根據官方發布的路線圖信息,現在也有放棄永久代并“搬家”

    Native Memory 來實現方法區的規劃了。

     

    Java 虛擬機規范對這個區域的限制非常寬松,除了和Java 堆一樣不需要連續的內

    存和可以選擇固定大小或者可擴展外,還可以選擇不實現垃圾收集。相對而言,垃圾

    收集行為在這個區域是比較少出現的,但并非數據進入了方法區就如永久代的名字一

    樣“永久”存在了。這個區域的內存回收目標主要是針對常量池的回收和對類型的卸

    載,一般來說這個區域的回收“成績”比較難以令人滿意,尤其是類型的卸載,條件

    相當苛刻,但是這部分區域的回收確實是有必要的。在Sun 公司的BUG 列表中,曾出

    現過的若干個嚴重的BUG 就是由于低版本的HotSpot 虛擬機對此區域未完全回收而導

    致內存泄漏。

    根據Java 虛擬機規范的規定, 當方法區無法滿足內存分配需求時, 將拋出

    OutOfMemoryError 異常。

     

    1.2.6     運行時常量池

     

    運行時常量池(Runtime Constant Pool)是方法區的一部分。Class 文件中除了有

    類的版本、字段、方法、接口等描述等信息外,還有一項信息是常量池(Constant Pool

    Table),用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后存放

    到方法區的運行時常量池中。

     

    Java 虛擬機對Class 文件的每一部分(自然也包括常量池)的格式都有嚴格的規

    定,每一個字節用于存儲哪種數據都必須符合規范上的要求,這樣才會被虛擬機認可、

    裝載和執行。但對于運行時常量池,Java 虛擬機規范沒有做任何細節的要求,不同的

    提供商實現的虛擬機可以按照自己的需要來實現這個內存區域。不過,一般來說,除

    了保存Class 文件中描述的符號引用外,還會把翻譯出來的直接引用也存儲在運行時常

    量池中。

     

    運行時常量池相對于Class 文件常量池的另外一個重要特征是具備動態性,Java

    言并不要求常量一定只能在編譯期產生,也就是并非預置入Class 文件中常量池的內容

    才能進入方法區運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發

    人員利用得比較多的便是String 類的intern() 方法。

     

    既然運行時常量池是方法區的一部分,自然會受到方法區內存的限制,當常量池無

    法再申請到內存時會拋出OutOfMemoryError 異常

    1.2.7     直接內存

    直接內存(Direct Memory)并不是虛擬機運行時數據區的一部分,也不是Java

    虛擬機規范中定義的內存區域,但是這部分內存也被頻繁地使用,而且也可能導致

    OutOfMemoryError 異常出現,所以我們放到這里一起講解。

    JDK 1.4 中新加入了NIONew Input/Output)類,引入了一種基于通道(Channel

    與緩沖區(Buffer)的I/O 方式,它可以使用Native 函數庫直接分配堆外內存,然

    后通過一個存儲在Java 堆里面的DirectByteBuffer 對象作為這塊內存的引用進行

    操作。這樣能在一些場景中顯著提高性能,因為避免了在Java 堆和Native 堆中來

    回復制數據。

    顯然,本機直接內存的分配不會受到Java 堆大小的限制,但是,既然是內存,則

    肯定還是會受到本機總內存(包括RAM SWAP 區或者分頁文件)的大小及處理器

    尋址空間的限制。服務器管理員配置虛擬機參數時,一般會根據實際內存設置-Xmx

    等參數信息,但經常會忽略掉直接內存,使得各個內存區域的總和大于物理內存限制

    (包括物理上的和操作系統級的限制),從而導致動態擴展時出現OutOfMemoryError

    異常。

     

    好了,到現在為止,我們已經弄明白了JVM的內存結構,下一章將對堆內存進行深入的學習。

    posted on 2012-03-14 09:40 草原上的駱駝 閱讀(2584) 評論(0)  編輯  收藏 所屬分類: JAVA基礎知識

    主站蜘蛛池模板: 亚洲熟女乱色一区二区三区| 亚洲国产成人一区二区精品区 | 中文字幕精品无码亚洲字| 婷婷亚洲综合一区二区| 国产美女无遮挡免费视频网站 | 久久久久久夜精品精品免费啦| 久久久久亚洲AV成人无码| 国产精品99久久免费观看| 亚洲AV无码乱码国产麻豆穿越 | 最近中文字幕免费mv在线视频| 久久精品国产亚洲| 99爱视频99爱在线观看免费| 亚洲综合久久成人69| 中国在线观看免费国语版| 久久亚洲国产最新网站| 日韩精品视频免费在线观看| 免费大片av手机看片| 亚洲一区二区精品视频| 国产午夜成人免费看片无遮挡 | 中文字幕乱码亚洲无线三区 | 午夜精品在线免费观看| 美女被免费网站视频在线| 国产亚洲精品免费| 亚洲视频在线免费| 国产精品免费高清在线观看| 亚洲成a人片在线观看中文!!! | 免费黄色大片网站| 一区二区三区免费在线视频| 亚洲熟妇丰满多毛XXXX| 亚洲精品在线免费观看| 亚洲AV无码AV日韩AV网站| 中文字幕亚洲不卡在线亚瑟| 中文字幕视频免费| 国产一区二区三区亚洲综合| 亚洲Av无码专区国产乱码DVD | a在线视频免费观看在线视频三区| 久久久久亚洲AV成人无码网站| 成人免费一区二区无码视频| 亚洲五月午夜免费在线视频| 亚洲人成电影网站| 亚洲中文字幕无码永久在线|