java 面試知識點筆記(三)底層知識 jvm 內存模型 下篇

 

上一篇講完了java內存模型中線程私有部分(程序計數器、虛擬機棧、本地方法棧),這篇講下全部線程公有部分html

問:元空間(MetaSpace)和永久代(PermGen)的區別?java

  • 元空間使用本地內存,而永久代使用的是jvm的內存

jdk8之後將類的元數據放在本地堆內存中,就是元空間MetaSpace,該空間jdk之前是屬於永久代的。8之後沒有OutOfMemoryError:PermGen space算法

元空間和永久代都是存放class的相關信息,包括class和Meta、field的信息。數組

元空間和永久代都是方法區的實現,只是實現不一樣,因此說方法區只是JVM的一種規範。數據結構

JDK1.7以後原先位於方法區中的字符串常量池已經移動到了堆中。jdk8之後使用元空間(MetaSpace)替代永久代(PermGen),由於元空間劃分更合理,好比說類及相關的元數據和類加載器生命週期一致,每一個加載器都會分配一個單獨的內存空間。併發

MetaSpace相比PermGen的優點jvm

  • 字符串常量池存在永久代中,容易出現性能問題和內存溢出
  • 類的方法信息大小難肯定,給永久代的大小置頂帶來困難(過小會出現永久代溢出,太大容易致使老年代溢出)
  • 永久代會爲GC帶來沒必要要的複雜性,回收效率低(永久代中的元數據的可能會隨着full GC發生而進行移動,比較消耗虛擬機性能。HotSpot虛擬機的每種類型的垃圾回收器都須要特殊處理永久代中的元數據。將元數據從永久代剝離出來,不只實現了對元空間的無縫管理,還能夠簡化Full GC以及對之後的併發隔離類元數據等方面進行優化)
  • 方便HotSpot與其餘JVM如Jrockit的集成(永久代是hotspot特有的,別的VM沒有永久代)

Java堆(Heap):性能

  • 對象實例的分配區域(heap是個大頭,佔用最多的內存空間。xmx設置jvm最大可用內存)
  • GC管理的主要區域(因此也稱爲GC堆)

jvm虛擬機規範裏,java堆可使用不連續的內存空間,只要邏輯上連續便可,就像磁盤空間同樣。堆空間能夠是固定大小,也能夠是動態擴展的(主流的虛擬機都是動態的)。若是堆中沒有內存完成實例分配,且堆不能再擴展時將會拋出OutOfMemoryError異常優化

主流的垃圾回收機制都是採用分代收集算法,因此堆能夠分爲新生代、老年代,再細點就有eden區、from survivor區、to survivor區,後面博客中GC再細講。spa

 

問:jvm三大新能調優參數 -Xms -Xmx -Xss的含義?

  1. -Xss:規定了每一個線程虛擬機棧(堆棧)的大小(通常256k足夠,此設置會影響併發線程數大小)
  2. -Xms:堆的初始值(就是jvm進程剛啓動的時候分配的堆空間大小,後面運行時堆空間超過初始值,就會動態擴容至堆的最大空間)
  3. -Xmx:堆能達到的最大值(通常xms xmx 都設置成同樣的,由於xms不夠用時動態擴容,會發生內存抖動,影響程序穩定性)

問:java內存模型中堆和棧的區別?

首先須要明白 內存分配策略:

  1. 靜態存儲:編譯時肯定每一個數據目標在運行時的存儲空間需求(這種分配策略要求程序不容許有可變存儲空間的結構存在,也不容許有嵌套、遞歸的結構存在。由於它們都會致使編譯時沒法計算準確的存儲空間)
  2. 棧式存儲:數據區需求在編譯時未知,運行時模塊入口前肯定(動態的存儲分配,是由一個相似於堆棧的運行棧實現的,和靜態的分配方式相反。可是進入一個程序模塊的時候必須知道該模塊的存儲大小,才能對其分配內存。跟棧同樣按照新進後出的方式分配內存)
  3. 堆式存儲:編譯時或運行時模塊入口都沒法肯定存儲空間,須要動態分配(好比可變長度串、對象實例。堆由大片的可利用快或空閒塊組成,堆中的內存能夠按照任意順序分配和釋放)

堆和棧的區別:

  • 聯繫:引用對象、數組時、棧裏定義變量保存堆中目標的首地址(棧只存引用變量,相似指針,程序使用棧中的引用變量訪問堆中的對象、數組。引用變量是普通變量,定義時在棧中分配,引用變量在程序運行到程序做用域以外後就會被釋放掉,而數組、對象自己在堆中分配,即便程序運行到做用域以外(new或者產生數組的代碼塊以外)堆中的數組、對象的內存不會被釋放,以後會被垃圾回收掉)
  • 管理方式:棧自動釋放,堆須要GC(JVM本身能夠針對內存棧進行管理操做,並且該內存空間的釋放是編譯器就能夠操做的內容。而堆空間在java中,jvm執行引擎是不會對其釋放的操做,而是讓GC回收)
  • 空間大小:棧比堆小(棧裏面存儲的數據和自己須要的數據特性決定的。堆須要存儲比較多的對象數據,通常都很大)
  • 碎片相關:棧產生的碎片遠小於堆(堆空間的活動空間至關於棧比較大,可能存在長期的內存分配和釋放操做,並且GC不是實時的,這使得堆中的碎片逐漸累積起來。棧空間自己就是堆棧數據結構,它的操做都是一一對應的,並且內存結構相對於堆空間的簡單,不容易產生碎片)
  • 分配方式:棧支持靜態和動態分配,而堆僅支持動態分配
  • 效率:棧的效率高於堆(由於內存塊自己就是個堆棧的結構,和棧空間的結構相符合,操做也簡單,只存在入棧出棧兩個操做。相對於堆空間,棧空間的靈活程度不夠,特別是動態管理的時候,而堆空間最大優勢就是動態分配,由於它在計算機底層多是個雙向鏈表的結構,因此管理的時候操做比棧複雜不少,因此堆的效率低於棧,可是靈活度高了不少)

例子:

 

問:不一樣JDK版本的intern()方法的區別?(主要是JDK6 VS JDK6+)String.intern()是一個Native方法,底層調用C++的 StringTable::intern 方法,源碼註釋:當調用 intern 方法時,若是常量池中已經該字符串,則返回池中的字符串;不然將此字符串添加到常量池中,並返回字符串的引用。

例子:

JDK6的時候存在永久代,因此VM options能夠設置PermSize大小

運行就會內存溢出,這也證實了JDK6存在永久代且永久代裏面由字符串常量池

JDK7 永久代移到堆中了 因此沒有內存溢出的錯誤

JDK8 也能輸出Mission Complete 可是沒有永久代的設置了 

intern在jdk6和6+的區別

jdk7+是

jdk6是

詳情請看:https://www.jianshu.com/p/0d1c003d2ff5 或者 https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html

相關文章
相關標籤/搜索