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

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

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

    道常無(wú)名

    玄之又玄,眾眇之門(mén)

      BlogJava :: 首頁(yè) :: 聯(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ū)、堆、程序計(jì)數(shù)器。但不同的資料和書(shū)籍上對(duì)于后三者的中文譯名不盡相同,這里將它們分別譯作:Java 方法棧、原生方法棧和直接內(nèi)存區(qū)。對(duì)于不同的 JVM,內(nèi)存區(qū)域劃分可能會(huì)有所差異,比如 Hot Spot 就將 Java 方法棧和原生方法棧合二為一,我們可以統(tǒng)稱(chēng)為方法棧(Method Stack)

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

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

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

    二、指令、方法與屬性


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

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

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

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

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

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


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

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

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

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


    前面提到對(duì)象實(shí)例以及動(dòng)態(tài)屬性都是保存在Heap 中的,而Heap 必須通過(guò)Stack中的地址指針才能夠被指令(類(lèi)的方法)訪問(wèn)到。因此可以推斷出:靜態(tài)屬性是保存在Stack中的,而不同于動(dòng)態(tài)屬性保存在Heap 中。正因?yàn)槎际窃赟tack中,而Stack中指令和數(shù)據(jù)都是定長(zhǎng)的,因此很容易算出偏移量,也因此不管什么指令(類(lèi)的方法),都可以訪問(wèn)到類(lèi)的靜態(tài)屬性。也正因?yàn)殪o態(tài)屬性被保存在Stack中,所以具有了全局屬性。

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

    三、Stack 棧


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

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

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

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

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

    四、Heap 堆


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

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

    4.1 Generation


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

    Perm

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

    Tenured

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

    Young

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

    4.2 Sizing the Generations


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

    Total Heap

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

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

    -Xmx -Xms之差就是三個(gè)Virtual空間的大小

    Young Generation

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

    堆內(nèi)存

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

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

    Perm Generation

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

    Thread Stack

    -XX:Xss=128K

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


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

    六、Method Area 方法區(qū)


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

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

    6.1 常量池 (constant pool)


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

    ◆類(lèi)和接口的全限定名;

    ◆字段的名稱(chēng)和描述符;

    ◆方法和名稱(chēng)和描述符。

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

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

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


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

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


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


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


    圖1 句柄方式


    圖2 直接方式

    原生方法棧與 Java 方法棧相類(lèi)似,這里不再贅述。


    八、JVM運(yùn)行原理 例子


    以上都是純理論,我們舉個(gè)例子來(lái)說(shuō)明 JVM 的運(yùn)行原理,我們來(lái)寫(xiě)一個(gè)簡(jiǎn)單的類(lèi),代碼如下:
    1. public class JVMShowcase {  
    2. //靜態(tài)類(lèi)常量,  
    3. public final static String ClASS_CONST = "I'm a Const";  
    4. //私有實(shí)例變量  
    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. }  


    這個(gè)類(lèi)沒(méi)有任何意義,不用猜測(cè)這個(gè)類(lèi)是做什么用,只是寫(xiě)一個(gè)比較典型的類(lèi),然后我們來(lái)看
    看 JVM 是如何運(yùn)行的,也就是輸入 java JVMShow 后,我們來(lái)看 JVM 是如何處理的:

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

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

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

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

    Heap 是空,Stack 是空,因?yàn)檫€沒(méi)有線程被執(zhí)行。Class Loader 通知 Execution Enginer 已經(jīng)加
    載完畢。

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


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

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

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


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


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

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

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

    問(wèn):我聽(tīng)說(shuō)類(lèi)變量是在 JVM 啟動(dòng)時(shí)就初始化好的,和你這說(shuō)的不同呀!
    答:那你是道聽(tīng)途說(shuō),信我的,沒(méi)錯(cuò)。
         的方法(函數(shù))到底是傳值還是傳址值還是傳址?

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

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

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

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

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

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

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

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

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

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

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

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

    只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲黄色网址在线观看| 亚洲国产精品精华液| 免费国产黄网站在线看| 久久w5ww成w人免费| 婷婷综合缴情亚洲狠狠尤物| 亚洲天堂中文资源| 四虎精品免费永久免费视频| 91香蕉成人免费网站| 亚洲一区爱区精品无码| 中文有码亚洲制服av片| 日本道免费精品一区二区| 精品国产免费观看| 亚洲自偷自偷精品| 亚洲sm另类一区二区三区| 一级毛片免费观看| 日本高清免费不卡在线| 久久亚洲精品人成综合网| 成人免费视频一区二区| 免费无码AV电影在线观看| 亚洲V无码一区二区三区四区观看| 久久亚洲色WWW成人欧美| 亚州免费一级毛片| 亚洲福利视频一区| a视频在线观看免费| 国产亚洲一区区二区在线| 国产精品亚洲小说专区| 看全色黄大色大片免费久久 | 久久精品国产亚洲av四虎| 亚洲第一视频在线观看免费| 免费一级毛片女人图片| 亚洲日韩国产二区无码| 无码国产精品一区二区免费I6| 亚洲视频一区二区三区| 午夜无码A级毛片免费视频| 亚洲AV综合色一区二区三区| 91视频免费观看| 亚洲女同成av人片在线观看| 久青草视频在线观看免费| 在线观看亚洲成人| 黄色视频在线免费观看| 久久精品国产亚洲精品|