話很少說,幹就完了。java
方法區同Java堆同樣,也是線程共享區域。方法區主要存儲已經被虛擬機加載的類信息(包括類的名稱、方法信息、字段信息)、常量、靜態變量、即時編譯器編譯後的代碼(好比spring 使用IOC或者AOP建立bean時,或者使用cglib,反射的形式動態生成class信息等)等數據。spring
不少人又把方法區稱爲"永久代",其實這個說法並不等價。僅僅是由於HotSpot虛擬機選擇把GC分代收集拓展到方法區,或者說是使用永久代來實現方法區而已。對於其餘的虛擬機來講是不存在永久代的概念的。線程
方法區除了和堆同樣能夠不須要連續的內存,也能夠選擇固定的大小或者動態拓展,還可以選擇是否實現垃圾收集。垃圾收集相對來講在方法區會比較少的出現。較少的出現並不意味着不會出現垃圾收集內存回收的狀況,方法區的垃圾收集主要是針對常量池的回收和類型的寫在。指針
若方法區沒法知足內存分配需求時,會拋出OOM異常。cdn
運行時常量池是屬於方法區的一部分,一般存儲的是在編譯期所產生的字面量及符號引用,以下圖所示:對象
在說到類加載子系統時,類的加載由加載、連接(驗證、準備、解析)、初始化、使用等這麼幾個階段,而在類加載階段,主要作了如下幾件事情:blog
可是須要特別說明的是,類加載階段所產生的類對象和實例對象本質上是有區別的。類對象僅僅是在類加載的時候生成到內存中的對象,而實例對象通常是經過new關鍵字所建立的對象。它們的內存存儲區域也不同。在上述步驟2中,所謂靜態存儲結構加載到運行時數據區中其實際上就是將class常量池中的內容保存到運行時常量池中。內存
常量池中還保存這符號引用,在類的解析階段,會將這些符號引用轉換成直接引用(直接指向對象實例的指針地址)保存到常量池中。因此,在整個類加載階段,有兩個環節會將數據保存至常量池中。字符串
運行時常量池相對於類常量池另外一個重要的特徵就是具有動態性,Java並不要求常量必定要在編譯器就產生,也就是說並非必定要在class常量池中的內容纔可以進入到運行時常量池,在程序運行期間,也可能將常量放入到常量池中。例如String類的intern()方法。編譯器
常量池屬於方法區的一部分那麼也是線程共享的,既然內存區域是共享的,那麼某種程度上就減輕了新對象頻繁建立銷燬的內存開銷,實現對象的共享。
例如字符串常量池:把全部字符串常量放到一個常量池中
運行時常量池屬於方法區的一部分,因此同方法區同樣,當出現內存不足時,也會出現OOM異常。
不怕路歹行不怕大雨淋,心上一字敢 面對個人夢,甘願來做憨人。 --<憨人>