道常無名

          玄之又玄,眾眇之門

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            16 Posts :: 0 Stories :: 1 Comments :: 0 Trackbacks
          轉(zhuǎn)載自:http://blog.csdn.net/vernonzheng/article/details/8458483

          一、JVM內(nèi)存區(qū)域劃分


          大多數(shù) JVM 將內(nèi)存區(qū)域劃分為 Method Area(Non-Heap),Heap,Program Counter RegisterJava Method Stack,Native Method StackDirect Memomry(注意 Directory Memory 并不屬于 JVM 管理的內(nèi)存區(qū)域)。前三者一般譯為:方法區(qū)、堆、程序計數(shù)器。但不同的資料和書籍上對于后三者的中文譯名不盡相同,這里將它們分別譯作:Java 方法棧、原生方法棧和直接內(nèi)存區(qū)。對于不同的 JVM,內(nèi)存區(qū)域劃分可能會有所差異,比如 Hot Spot 就將 Java 方法棧和原生方法棧合二為一,我們可以統(tǒng)稱為方法棧(Method Stack)

          深入JVM系列(一)之內(nèi)存模型與內(nèi)存分配 - hubingforever - 民主與科學(xué)
           

          首先我們熟悉一下一個一般性的 Java 程序的工作過程。一個 Java 源程序文件,會被編譯為字節(jié)碼文件(以 class 為擴(kuò)展名),然后告知 JVM 程序的運行入口,再被 JVM 通過字節(jié)碼解釋器加載運行。那么程序開始運行后,都是如何涉及到各內(nèi)存區(qū)域的呢?

          概括地說來,JVM 每遇到一個線程,就為其分配一個程序計數(shù)器、Java 方法棧和原生方法棧。當(dāng)線程終止時,兩者所占用的內(nèi)存空間也會被釋放掉。棧中存儲的是棧幀,可以說每個棧幀對應(yīng)一個“運行現(xiàn)場”。在每個“運行現(xiàn)場”中,如果出現(xiàn)了一個局部對象,則它的實例數(shù)據(jù)被保存在堆中,而類數(shù)據(jù)被保存在方法區(qū)。

          二、指令、方法與屬性


          在講各部分之前,我們首先要搞清楚的是什么是數(shù)據(jù)以及什么是指令。然后要搞清楚對象的方法和對象的屬性分別保存在哪里。

          1)方法本身是指令的操作碼部分,保存在Stack中;

          2)方法內(nèi)部變量作為指令的操作數(shù)部分,跟在指令的操作碼之后,保存在Stack中(實際上是簡單類型保存在Stack中,對象類型在Stack中保存地址,在Heap 中保存值);上述的指令操作碼和指令操作數(shù)構(gòu)成了完整的Java 指令。

          3)對象實例包括其屬性值作為數(shù)據(jù),保存在數(shù)據(jù)區(qū)Heap 中。

          非靜態(tài)的對象屬性作為對象實例的一部分保存在Heap 中,而對象實例必須通過Stack中保存的地址指針才能訪問到。因此能否訪問到對象實例以及它的非靜態(tài)屬性值完全取決于能否獲得對象實例在Stack中的地址指針。

          非靜態(tài)方法和靜態(tài)方法的區(qū)別:


          非靜態(tài)方法有一個和靜態(tài)方法很重大的不同:非靜態(tài)方法有一個隱含的傳入?yún)?shù),該參數(shù)是JVM給它的,和我們怎么寫代碼無關(guān),這個隱含的參數(shù)就是對象實例在Stack中的地址指針。因此非靜態(tài)方法(在Stack中的指令代碼)總是可以找到自己的專用數(shù)據(jù)(在Heap 中的對象屬性值)。當(dāng)然非靜態(tài)方法也必須獲得該隱含參數(shù),因此非靜態(tài)方法在調(diào)用前,必須先new一個對象實例,獲得Stack中的地址指針,否則JVM將無法將隱含參數(shù)傳給非靜態(tài)方法。

          靜態(tài)方法無此隱含參數(shù),因此也不需要new對象,只要class文件被ClassLoader load進(jìn)入JVM的Stack,該靜態(tài)方法即可被調(diào)用。當(dāng)然此時靜態(tài)方法是存取不到Heap 中的對象屬性的。

          總結(jié)一下該過程:當(dāng)一個class文件被ClassLoader load進(jìn)入JVM后,方法指令保存在Stack中,此時Heap 區(qū)沒有數(shù)據(jù)。然后程序技術(shù)器開始執(zhí)行指令,如果是靜態(tài)方法,直接依次執(zhí)行指令代碼,當(dāng)然此時指令代碼是不能訪問Heap 數(shù)據(jù)區(qū)的;如果是非靜態(tài)方法,由于隱含參數(shù)沒有值,會報錯。因此在非靜態(tài)方法執(zhí)行前,要先new對象,在Heap 中分配數(shù)據(jù),并把Stack中的地址指針交給非靜態(tài)方法,這樣程序技術(shù)器依次執(zhí)行指令,而指令代碼此時能夠訪問到Heap 數(shù)據(jù)區(qū)了。

          靜態(tài)屬性和動態(tài)屬性:


          前面提到對象實例以及動態(tài)屬性都是保存在Heap 中的,而Heap 必須通過Stack中的地址指針才能夠被指令(類的方法)訪問到。因此可以推斷出:靜態(tài)屬性是保存在Stack中的,而不同于動態(tài)屬性保存在Heap 中。正因為都是在Stack中,而Stack中指令和數(shù)據(jù)都是定長的,因此很容易算出偏移量,也因此不管什么指令(類的方法),都可以訪問到類的靜態(tài)屬性。也正因為靜態(tài)屬性被保存在Stack中,所以具有了全局屬性。

          在JVM中,靜態(tài)屬性保存在Stack指令內(nèi)存區(qū),動態(tài)屬性保存在Heap數(shù)據(jù)內(nèi)存區(qū)。

          三、Stack 棧


          Stack(棧)是JVM的內(nèi)存指令區(qū)。Stack管理很簡單,push一定長度字節(jié)的數(shù)據(jù)或者指令,Stack指針壓棧相應(yīng)的字節(jié)位移;pop一定字節(jié)長度數(shù)據(jù)或者指令,Stack指針彈棧。Stack的速度很快,管理很簡單,并且每次操作的數(shù)據(jù)或者指令字節(jié)長度是已知的。所以Java 基本數(shù)據(jù)類型,Java 指令代碼,常量都保存在Stack中。

          棧也叫棧內(nèi)存,是 Java 程序的運行區(qū),是在線程創(chuàng)建時創(chuàng)建,它的生命期是跟隨線程的生命
          ,線程結(jié)束棧內(nèi)存也就釋放,對于棧來說不存在垃圾回收問題,只要線程一結(jié)束,該棧就 Over。

          那么棧中存的是那些數(shù)據(jù)呢?又什么是格式呢?

          棧中的數(shù)據(jù)都是以棧幀(Stack Frame)的格式存在,棧幀是一個內(nèi)存區(qū)塊,是一個數(shù)據(jù)集,是
          一個有關(guān)方法(Method)和運行期數(shù)據(jù)的數(shù)據(jù)集,當(dāng)一個方法 A 被調(diào)用時就產(chǎn)生了一個棧幀 F1,并
          被壓入到棧中,A 方法又調(diào)用了 B 方法,于是產(chǎn)生棧幀 F2 也被壓入棧,執(zhí)行完畢后,先彈出 F2
          棧幀,再彈出 F1 棧幀,遵循“先進(jìn)后出”原則。

          那棧幀中到底存在著什么數(shù)據(jù)呢?棧幀中主要保存 3 類數(shù)據(jù):本地變量(Local Variables),
          包括輸入?yún)?shù)和輸出參數(shù)以及方法內(nèi)的變量;棧操作(Operand Stack),記錄出棧、入棧的操作;
          棧幀數(shù)據(jù)(Frame Data),包括類文件、方法等等。光說比較枯燥,我們畫個圖來理解一下 Java
          棧,如下圖所示:
           

          四、Heap 堆


          Heap(堆)是JVM的內(nèi)存數(shù)據(jù)區(qū)。Heap 的管理很復(fù)雜,每次分配不定長的內(nèi)存空間,專門用來保存對象的實例。在Heap 中分配一定的內(nèi)存來保存對象實例,實際上也只是保存對象實例的屬性值,屬性的類型和對象本身的類型標(biāo)記等,并不保存對象的方法(方法是指令,保存在Stack中),在Heap 中分配一定的內(nèi)存保存對象實例和對象的序列化比較類似。而對象實例在Heap 中分配好以后,需要在Stack中保存一個4字節(jié)的Heap 內(nèi)存地址,用來定位該對象實例在Heap 中的位置,便于找到該對象實例。

          Java中堆是由所有的線程共享的一塊內(nèi)存區(qū)域。

          4.1 Generation


          JVM堆一般又可以分為以下三部分:

          Perm

          Perm代主要保存class,method,filed對象,這部門的空間一般不會溢出,除非一次性加載了很多的類,不過在涉及到熱部署的應(yīng)用服務(wù)器的時候,有時候會遇到j(luò)ava.lang.OutOfMemoryError : PermGen space 的錯誤,造成這個錯誤的很大原因就有可能是每次都重新部署,但是重新部署后,類的class沒有被卸載掉,這樣就造成了大量的class對象保存在了perm中,這種情況下,一般重新啟動應(yīng)用服務(wù)器可以解決問題。

          Tenured

          Tenured區(qū)主要保存生命周期長的對象,一般是一些老的對象,當(dāng)一些對象在Young復(fù)制轉(zhuǎn)移一定的次數(shù)以后,對象就會被轉(zhuǎn)移到Tenured區(qū),一般如果系統(tǒng)中用了application級別的緩存,緩存中的對象往往會被轉(zhuǎn)移到這一區(qū)間。

          Young

          Young區(qū)被劃分為三部分,Eden區(qū)和兩個大小嚴(yán)格相同的Survivor區(qū),其中Survivor區(qū)間中,某一時刻只有其中一個是被使用的,另外一個留做垃圾收集時復(fù)制對象用,在Young區(qū)間變滿的時候,minor GC就會將存活的對象移到空閑的Survivor區(qū)間中,根據(jù)JVM的策略,在經(jīng)過幾次垃圾收集后,任然存活于Survivor的對象將被移動到Tenured區(qū)間。

          4.2 Sizing the Generations


          JVM提供了相應(yīng)的參數(shù)來對內(nèi)存大小進(jìn)行配置。正如上面描述,JVM中堆被分為了3個大的區(qū)間,同時JVM也提供了一些選項對Young,Tenured的大小進(jìn)行控制。

          Total Heap

          -Xms :指定了JVM初始啟動以后初始化內(nèi)存

          -Xmx:指定JVM堆得最大內(nèi)存,在JVM啟動以后,會分配-Xmx參數(shù)指定大小的內(nèi)存給JVM,但是不一定全部使用,JVM會根據(jù)-Xms參數(shù)來調(diào)節(jié)真正用于JVM的內(nèi)存

          -Xmx -Xms之差就是三個Virtual空間的大小

          Young Generation

          -XX:NewRatio=8意味著tenured 和 young的比值8:1,這樣eden+2*survivor=1/9

          堆內(nèi)存

          -XX:SurvivorRatio=32意味著eden和一個survivor的比值是32:1,這樣一個Survivor就占Young區(qū)的1/34.

          -Xmn 參數(shù)設(shè)置了年輕代的大小

          Perm Generation

          -XX:PermSize=16M -XX:MaxPermSize=64M

          Thread Stack

          -XX:Xss=128K

          五、The pc Register 程序計數(shù)器寄存器


          JVM支持多個線程同時運行。每個JVM都有自己的程序計數(shù)器。在任何一個點,每個JVM線程執(zhí)行單個方法的代碼,這個方法是線程的當(dāng)前方法。如果方法不是native的,程序計數(shù)器寄存器包含了當(dāng)前執(zhí)行的JVM指令的地址,如果方法是 native的,程序計數(shù)器寄存器的值不會被定義。 JVM的程序計數(shù)器寄存器的寬度足夠保證可以持有一個返回地址或者native的指針。

          六、Method Area 方法區(qū)


          Object Class Data(類定義數(shù)據(jù)) 是存儲在方法區(qū)的。除此之外,常量、靜態(tài)變量、JIT 編譯后的代碼也都在方法區(qū)。正因為方法區(qū)所存儲的數(shù)據(jù)與堆有一種類比關(guān)系,所以它還被稱為 Non-Heap。方法區(qū)也可以是內(nèi)存不連續(xù)的區(qū)域組成的,并且可設(shè)置為固定大小,也可以設(shè)置為可擴(kuò)展的,這點與堆一樣。

          方法區(qū)內(nèi)部有一個非常重要的區(qū)域,叫做運行時常量池(Runtime Constant Pool,簡稱 RCP)。在字節(jié)碼文件中有常量池(Constant Pool Table),用于存儲編譯器產(chǎn)生的字面量和符號引用。每個字節(jié)碼文件中的常量池在類被加載后,都會存儲到方法區(qū)中。值得注意的是,運行時產(chǎn)生的新常量也可以被放入常量池中,比如 String 類中的 intern() 方法產(chǎn)生的常量。

          6.1 常量池 (constant pool)


          常量池指的是在編譯期被確定,并被保存在已編譯的.class文件中的一些數(shù)據(jù)。除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數(shù)組)的常量值(final)還包含一些以文本形式出現(xiàn)的符號引用,比如:

          ◆類和接口的全限定名;

          ◆字段的名稱和描述符;

          ◆方法和名稱和描述符。

          虛擬機(jī)必須為每個被裝載的類型維護(hù)一個常量池。常量池就是該類型所用到常量的一個有序集和,包括直接常量(string,integer和 floating point常量)和對其他類型,字段和方法的符號引用。

          對于String常量,它的值是在常量池中的。而JVM中的常量池在內(nèi)存當(dāng)中是以表的形式存在的, 對于String類型,有一張固定長度的CONSTANT_String_info表用來存儲文字字符串值,注意:該表只存儲文字字符串值,不存儲符號引 用。說到這里,對常量池中的字符串值的存儲位置應(yīng)該有一個比較明了的理解了。
          在程序執(zhí)行的時候,常量池 會儲存在Method Area,而不是堆中。

          七、Java Method Stack Java 方法棧 與 Native Method Stack 原生方法棧


          第七章內(nèi)容來源:http://blog.csdn.net/poechant/article/details/7289093

          Java 方法棧也是線程私有的,每個 Java 方法棧都是由一個個棧幀組成的,每個棧幀是一個方法運行期的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),它存儲著局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。當(dāng)線程調(diào)用調(diào)用了一個 Java 方法時,一個棧幀就被壓入(push)到相應(yīng)的 Java 方法棧。當(dāng)線程從一個 Java 方法返回時,相應(yīng)的 Java 方法棧就彈出(pop)一個棧幀。


          其中要詳細(xì)介紹的是局部變量表,它保存者各種基本數(shù)據(jù)類型和對象引用(Object reference)。基本數(shù)據(jù)類型包括 boolean、byte、char、short、int、long、float、double。對象引用,本質(zhì)就是一個地址(也可以說是一個“指針”),該地址是堆中的一個地址,通過這個地址可以找到相應(yīng)的 Object(注意是“找到”,原因會在下面解釋)。而這個地址找到相應(yīng) Object 的方式有兩種。一種是該地址存儲著 Pointer to Object Instance Data 和 Pointer to Object Class Data,另一種是該地址存儲著 Object Instance Data,其中又包含有 Pointer to Object Class Data。如下兩圖所示。


          第一種方式,Java 方法棧中有 Handler Pool 和 Instance Pool。無論哪種方式,Object Class Data 都是存儲在方法區(qū)的,Object Instance Data 都是存儲在堆中的。


          圖1 句柄方式


          圖2 直接方式

          原生方法棧與 Java 方法棧相類似,這里不再贅述。


          八、JVM運行原理 例子


          以上都是純理論,我們舉個例子來說明 JVM 的運行原理,我們來寫一個簡單的類,代碼如下:
          1. public class JVMShowcase {  
          2. //靜態(tài)類常量,  
          3. public final static String ClASS_CONST = "I'm a Const";  
          4. //私有實例變量  
          5. private int instanceVar=15;  
          6. public static void main(String[] args) {  
          7. //調(diào)用靜態(tài)方法  
          8. runStaticMethod();  
          9. //調(diào)用非靜態(tài)方法  
          10. JVMShowcase showcase=new JVMShowcase();  
          11. showcase.runNonStaticMethod(100);  
          12. }  
          13. //常規(guī)靜態(tài)方法  
          14. public static String runStaticMethod(){  
          15. return ClASS_CONST;  
          16. }  
          17. //非靜態(tài)方法  
          18. public int runNonStaticMethod(int parameter){  
          19. int methodVar=this.instanceVar * parameter;  
          20. return methodVar;  
          21. }  
          22. }  


          這個類沒有任何意義,不用猜測這個類是做什么用,只是寫一個比較典型的類,然后我們來看
          看 JVM 是如何運行的,也就是輸入 java JVMShow 后,我們來看 JVM 是如何處理的:

                 向操作系統(tǒng)申請空閑內(nèi)存。JVM 對操作系統(tǒng)說“給我 64M 空閑內(nèi)存”,于是第 1 步,JVM 向操作系統(tǒng)申請空閑內(nèi)存
          作系統(tǒng)就查找自己的內(nèi)存分配表,找了段 64M 的內(nèi)存寫上“Java 占用”標(biāo)簽,然后把內(nèi)存段的起始地址和終止地址給 JVM,JVM 準(zhǔn)備加載類文件。

          分配內(nèi)存內(nèi)存。第 2 步,JVM 分配內(nèi)存。JVM 獲得到 64M 內(nèi)存,就開始得瑟了,首先給 heap 分個內(nèi)存,并
          且是按照 heap 的三種不同類型分好的,然后給棧內(nèi)存也分配好。

                  文件。第 3 步,檢查和分析 class 文件。若發(fā)現(xiàn)有錯誤即返回錯誤。

               加載類。第 4 步,加載類。由于沒有指定加載器,JVM 默認(rèn)使用 bootstrap 加載器,就把 rt.jar 下的所有
          類都加載到了堆類存的永久存儲區(qū),JVMShow 也被加載到內(nèi)存中。我們來看看棧內(nèi)存,如下圖:

          Heap 是空,Stack 是空,因為還沒有線程被執(zhí)行。Class Loader 通知 Execution Enginer 已經(jīng)加
          載完畢。

               執(zhí)行引擎執(zhí)行方法。第 5 步,執(zhí)行引擎執(zhí)行 main 方法。執(zhí)行引擎啟動一個線程,開始執(zhí)行 main 方法,在 main 執(zhí)
          行完畢前,方法區(qū)如下圖所示:


          在 Method Area 加入了 CLASS_CONST 常量,它是在第一次被訪問時產(chǎn)生的。堆內(nèi)存中有兩個對象 object 和 showcase 對象,如下圖所示:

          為什么會有 Object 對象呢?是因為它是 JVMShowcase 的父類,JVM 是先初始化父類,然后再
          初始化子類,甭管有多少個父類都初始化。在棧內(nèi)存中有三個棧幀,如下圖所示:

          于此同時,還創(chuàng)建了一個程序計數(shù)器指向下一條要執(zhí)行的語句。
             
          釋放內(nèi)存。運第 6 步,釋放內(nèi)存。運行結(jié)束,JVM 向操作系統(tǒng)發(fā)送消息,說“內(nèi)存用完了,我還給你”
          行結(jié)束。


          九、JVM 相關(guān)問題


          問:堆和棧有什么區(qū)別堆和棧有什么區(qū)別有什么
          答:堆是存放對象的,但是對象內(nèi)的臨時變量是存在棧內(nèi)存中,如例子中的 methodVar 是在運
          行期存放到棧中的。
          棧是跟隨線程的,有線程就有棧,堆是跟隨 JVM 的,有 JVM 就有堆內(nèi)存。

          問:堆內(nèi)存中到底存在著什么東西?堆內(nèi)存中到底存在著什么東西?
          答:對象,包括對象變量以及對象方法。

          問:類變量和實例變量有什么區(qū)別?類變量和實例變量有什么區(qū)別?有什么區(qū)別
          答:靜態(tài)變量是類變量,非靜態(tài)變量是實例變量,直白的說,有 static 修飾的變量是靜態(tài)變量,
          沒有 static 修飾的變量是實例變量。靜態(tài)變量存在方法區(qū)中,實例變量存在堆內(nèi)存中。
               啟動時就初始化好的,和你這說的不同呀!

          問:我聽說類變量是在 JVM 啟動時就初始化好的,和你這說的不同呀!
          答:那你是道聽途說,信我的,沒錯。
               的方法(函數(shù))到底是傳值還是傳址值還是傳址?

          問:Java 的方法(函數(shù))到底是傳值還是傳址?
          答:都不是,是以傳值的方式傳遞地址,具體的說原生數(shù)據(jù)類型傳遞的值,引用類型傳遞的地
          址。對于原始數(shù)據(jù)類型,JVM 的處理方法是從 Method Area 或 Heap 中拷貝到 Stack,然后運行 frame
          中的方法,運行完畢后再把變量指拷貝回去。
                       產(chǎn)生?

          問:為什么會產(chǎn)生 OutOfMemory 產(chǎn)生?
          答:一句話:Heap 內(nèi)存中沒有足夠的可用內(nèi)存了。這句話要好好理解,不是說 Heap 沒有內(nèi)存
          了,是說新申請內(nèi)存的對象大于 Heap 空閑內(nèi)存,比如現(xiàn)在 Heap 還空閑 1M,但是新申請的內(nèi)存需
          要 1.1M,于是就會報 OutOfMemory 了,可能以后的對象申請的內(nèi)存都只要 0.9M,于是就只出現(xiàn)
          一次 OutOfMemory,GC 也正常了,看起來像偶發(fā)事件,就是這么回事。 但如果此時 GC 沒有回
          收就會產(chǎn)生掛起情況,系統(tǒng)不響應(yīng)了。

          問:我產(chǎn)生的對象不多呀,為什么還會產(chǎn)生 OutOfMemory?我產(chǎn)生的對象不多呀,?
          答:你繼承層次忒多了,Heap 中 產(chǎn)生的對象是先產(chǎn)生 父類,然后才產(chǎn)生子類,明白不?
                      錯誤分幾種?問:OutOfMemory 錯誤分幾種?
          答:分兩種,分別是“OutOfMemoryError:java heap size”和”OutOfMemoryError: PermGen
          space”,兩種都是內(nèi)存溢出,heap size 是說申請不到新的內(nèi)存了,這個很常見,檢查應(yīng)用或調(diào)整
          堆內(nèi)存大小。
          “PermGen space”是因為永久存儲區(qū)滿了,這個也很常見,一般在熱發(fā)布的環(huán)境中出現(xiàn),是
          因為每次發(fā)布應(yīng)用系統(tǒng)都不重啟,久而久之永久存儲區(qū)中的死對象太多導(dǎo)致新對象無法申請內(nèi)存,
          一般重新啟動一下即可。

          問:為什么會產(chǎn)生 StackOverflowError??
          答:因為一個線程把 Stack 內(nèi)存全部耗盡了,一般是遞歸函數(shù)造成的。
                   之間可以互訪嗎?

          問:一個機(jī)器上可以看多個 JVM 嗎?JVM 之間可以互訪嗎?
          答:可以多個 JVM,只要機(jī)器承受得了。JVM 之間是不可以互訪,你不能在 A-JVM 中訪問
          B-JVM 的 Heap 內(nèi)存,這是不可能的。在以前老版本的 JVM 中,會出現(xiàn) A-JVM Crack 后影響到
          B-JVM,現(xiàn)在版本非常少見。
                要采用垃圾回收機(jī)制,的顯式

          問:為什么 Java 要采用垃圾回收機(jī)制,而不采用 C/C++的顯式內(nèi)存管理?的顯 內(nèi)存管理?
          答:為了簡單,內(nèi)存管理不是每個程序員都能折騰好的。

          問:為什么你沒有詳細(xì)介紹垃圾回收機(jī)制?為什么你沒有詳細(xì)介紹垃圾回收機(jī)制
          答:垃圾回收機(jī)制每個 JVM 都不同,JVM Specification 只是定義了要自動釋放內(nèi)存,也就是
          說它只定義了垃圾回收的抽象方法,具體怎么實現(xiàn)各個廠商都不同,算法各異,這東西實在沒必要
          深入。
              中到底哪些區(qū)域是共享的?哪些是私有的?

          問:JVM 中到底哪些區(qū)域是共享的?哪些是私有的?
          答:Heap 和 Method Area 是共享的,其他都是私有的,

          問:什么是 JIT,你怎么沒說?,你怎么沒說?
          答:JIT 是指 Just In Time,有的文檔把 JIT 作為 JVM 的一個部件來介紹,有的是作為執(zhí)行引
          擎的一部分來介紹,這都能理解。Java 剛誕生的時候是一個解釋性語言,別噓,即使編譯成了字
          節(jié)碼(byte code)也是針對 JVM 的,它需要再次翻譯成原生代碼(native code)才能被機(jī)器執(zhí)行,于
          是效率的擔(dān)憂就提出來了。Sun 為了解決該問題提出了一套新的機(jī)制,好,你想編譯成原生代碼,
          沒問題,我在 JVM 上提供一個工具,把字節(jié)碼編譯成原生碼,下次你來訪問的時候直接訪問原生
          碼就成了,于是 JIT 就誕生了,就這么回事。
              還有哪些部分是你沒有提到的?

          問:JVM 還有哪些部分是你沒有提到的?
          答:JVM 是一個異常復(fù)雜的東西,寫一本磚頭書都不為過,還有幾個要說明的:
          常量池(constant pool)按照順序存放程序中的常量,:并且進(jìn)行索引編號的區(qū)域。比如 int i =100,
          這個 100 就放在常量池中。
          安全管理器(Security Manager):提供 Java 運行期的安全控制,防止惡意攻擊,比如指定讀取
          文件,寫入文件權(quán)限,網(wǎng)絡(luò)訪問,創(chuàng)建進(jìn)程等等,Class Loader 在 Security Manager 認(rèn)證通過后才
          能加載 class 文件的。
          方法索引表(Methods table),記錄的是每個 method 的地址信息,Stack 和 Heap 中的地址指針
          其實是指向 Methods table 地址。

          問:為什么不建議在程序中顯式的生命 System.gc()??
          答:因為顯式聲明是做堆內(nèi)存全掃描,也就是 Full GC,是需要停止所有的活動的(Stop The
          World Collection),你的應(yīng)用能承受這個嗎?

          問:JVM 有哪些調(diào)整參數(shù)?
          答:非常多,自己去找,堆內(nèi)存、棧內(nèi)存的大小都可以定義,甚至是堆內(nèi)存的三個部分、新生
          代的各個比例都能調(diào)整。
          posted on 2016-09-23 18:58 Linuxmouse 閱讀(172) 評論(0)  編輯  收藏 所屬分類: Java

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 保山市| 大英县| 龙南县| 台中市| 永宁县| 邵阳县| 镇坪县| 独山县| 清苑县| 武川县| 吴江市| 交口县| 江阴市| 海兴县| 额尔古纳市| 桃园市| 文山县| 泌阳县| 金寨县| 大宁县| 庆安县| 乐都县| 义马市| 上杭县| 弥渡县| 公主岭市| 木里| 潜山县| 祥云县| 达尔| 越西县| 周口市| 遵义市| 镇安县| 阳泉市| 长阳| 阳高县| 衡水市| 突泉县| 房产| 澜沧|