java字面量 方法区_(一)java的内存模型
程序計數器(私有)
程序計數器:"是一個非常小的內存空間,用來保證程序依次執行",它可以看作是當前線程所執行的字節碼的行號指示器 由于java虛擬機的多線程是通過線程輪流切換并分配處理器執行時間的方式來實現的,在切出后切回的時候需要一個標識。
棧 (私有) "基本類型、運算、方法服務、指向堆內存的指針"
虛擬機棧(‘執行的是java方法服務‘) 它的生命周期與線程相同。虛擬機棧描述的是Java方法執行的線程內存模型:每個方法被執行的時候,Java虛擬機都會同步創建一個棧幀 (Stack Frame)用于存儲局部變量表、操作數棧、動態連接、方法出口等信息。‘每一個方法被調用直至執行完畢的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。‘ 局部變量表: 存放了編譯期可知的各種Java虛擬機基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型, 它并不等同于對象本身,可能是一個指向對象起始地址的引用指針,也可能是指向一個代表對象的句柄或者其他與此對象相關的位置)和returnAddress類型(指向了一條字節碼指令的地址)。 ‘異常拋出‘ 如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常;如果Java虛擬機棧容量可以動態擴展,‘其實HotSpot虛擬機的棧容量是不可以動態擴展的‘ 當棧擴展時無法申請到足夠的內存會拋出OutOfMemoryError異常。 本地方法棧(‘執行的是虛擬機用到的native方法服務‘) 一個native方法就是一個Java調用非Java代碼的接口。 本地方法棧也會在棧深度溢出或者棧擴展失敗時分別拋出StackOverflowError和OutOfMemoryError異常。
堆 (共享)(-Xmx -Xms)("是垃圾收集器管理的主要區域。")
"堆內存用于存放由new創建的對象和數組,集合等,String new 出來和不是new出來的存儲地方不同。"保存所有引用數據的真實信息;存放對象實例,幾乎所有的對象都是存在堆中的,被‘所有的線程共享。‘ 包括原始類型的封裝類(如Byte、Integer、Long等等),‘不管對象是屬于一個成員變量還是方法中的本地變量,它都會被存儲在堆區。‘ 新生代和老年代 其中新生帶存放新生的對象或者年齡不大的對象,老年代則存放老年對象。 新生代分為eden區、s0區、s1區,"s0和s1也被稱為from和to區域,他們是兩塊大小相等并且可以互相角色的空間。" 絕大多數情況下,對象首先分配在eden區,在新生代回收后,如果對象還存活,則進入s0或s1區,之后每經過一次 新生代回收,如果對象存活則它的年齡就加1,對象達到一定的年齡后,則進入老年代。
堆棧的存儲
1、基礎數據類型直接在棧空間分配;
2、方法的形式參數,直接在棧空間分配,當方法調用完成后從棧空間回收;
3、引用數據類型,需要用 new 來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量;
4、方法的引用參數,在棧空間分配一個地址空間,并指向堆空間的對象區,當方法調用完后從棧空間回收;
5、局部變量 new 出來時,在棧空間和堆空間中分配空間,當局部變量生命周期結束后,棧空間立刻被回收,堆空間區域等待 GC 回收;
6、方法調用時傳入的實際參數,先在棧空間分配,在方法調用完成后從棧空間釋放;
7、字符串常量在 DATA 區域分配 , this 在堆空間分配;
8、數組在棧空間分配數組名稱, 在堆空間分配數組實際的大小!
9.‘Static類型的變量以及類本身相關信息都會隨著類本身存儲在堆區。
10.一個本地變量也有可能是一個對象的引用,這種情況下,這個本地引用會被存儲到棧中,但是對象本身仍然存儲在堆區。
11.對于一個對象的成員變量,不管它是原始類型還是包裝類型,都會被存儲到堆區。
12.堆中的對象可以被多線程共享。如果一個線程獲得一個對象的應用,它便可訪問這個對象的成員變量。如果兩個線程同時調用了同一個對象的同一個方法, 那么這兩個線程便可同時訪問這個對象的成員變量,但是對于本地變量,每個線程都會拷貝一份到自己的線程棧中。
方法區(共享)(描述為堆的一個邏輯部分)"所以定義的方法的信息都保存方法區中"
用于存儲已被虛擬機‘加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼緩存等數據。‘ 也就是所有編譯器能夠被確定,能夠被快速查找的內容都存放在這里,它像數組一樣通過索引訪問,就是專門用來做查找的" ‘元空間(替代永久代)‘ 元空間并不在虛擬機中,而是"使用本地內存"。 -XX:MetaspaceSize,初始空間大小,達到該值就會觸發垃圾收集進行類型卸載,同時GC會對該值進行調整:如果釋放了大量的空間,就適當降低該值; 如果釋放了很少的空間,那么在不超過MaxMetaspaceSize時,適當提高該值。 -XX:MaxMetaspaceSize,最大空間,默認是沒有限制的。 存儲的是每個class的信息: 1.類加載器引用(classLoader) 2.運行時常量池(是方法區的一部分,用于存儲編譯器生成的各種字面量和符號引用。) 所有常量、字段引用、方法引用、屬性 3.字段數據 每個方法的名字、類型(如類的全路徑名、類型或接口) 、修飾符(如public、abstract、final)、屬性 4.方法數據 每個方法的名字、返回類型、參數類型(按順序)、修飾符、屬性 5.方法代碼 每個方法的字節碼、操作數棧大小、局部變量大小、局部變量表、異常表和每個異常處理的開始位置、結 束位置、代碼處理在程序計數器中的偏移地址、被捕獲的異常類的常量池索引 為什么要使用元空間能代替永久代 1、字符串存在永久代中,容易出現性能問題和內存溢出。 2、類及方法的信息等比較難確定其大小,因此對于永久代的大小指定比較困難,太小容易出現永久代溢出,太大則容易導致老年代溢出。 3、永久代會為 GC 帶來不必要的復雜度,并且回收效率偏低。 方法區無法滿足新的內存分配需求時,將拋出OutOfMemoryError異常。
運行時常量池
有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池表(Constant Pool Table),用于存放編譯期生成的各種字面量與符號引用,‘總之就是裝載class文件。‘ 這部分內容將在類加載后存放到方法區的運行時常量池中。
常量池
常量池主要可以分為以下幾種: (1)靜態常量池:即*.class文件中的常量池,class文件中的常量池不僅僅包含字符串/數字這些字面量,還包含類、方法的信息,占用class文件絕大部分空間。 這種常量池主要用于存放兩大類常量:字面量和符號引用量,字面量相當于Java語言層面常量的概念,如文本字符串,聲明為final的常量值等;符號引用則屬于編譯原理? ? 方面的概念,包括了如下三種類型的常量:類和接口的全限定名、字段名稱描述符、方法名稱描述符。 ? ? ? ? 類的加載過程中的鏈接部分的解析步驟就是把符號引用替換為直接引用,即把那些描述符(名字)替換為能直接定位到字段、方法的引用或句柄(地址)。 (2)運行時常量池:虛擬機會將各個class文件中的常量池載入到運行時常量池中,即編譯期間生成的字面量、符號引用,總之就是裝載class文件。 字符串常量池 :字符串常量池可以理解為運行時常量池分出來的部分。加載時,對于class的靜態常量池,如果字符串會被裝到字符串常量池中。 整型常量池:Integer,類似字符串常量池,可以理解為運行時常量池分出來的。加載時,對于class的靜態常量池裝的東西,如果是整型會被裝到整型常量池中。 ? ? ? ? ? ? ? ?類似的還有Character、Long等等常量池(基本數據類型沒有哦)。。。
直接內存
不在虛擬機中,稱作堆外內存
總結
以上是生活随笔為你收集整理的java字面量 方法区_(一)java的内存模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java concurrentmap原理
- 下一篇: java memcached 存储对象_