大數據技術之_30_JVM學習_01_JVM 位置+JVM 體系結構概覽+堆體系結構概述+堆參數調優入門+JVM 的配置和優化+Tomcat 的配置和優化

1、JVM 位置2、JVM 體系結構概覽3、堆體系結構概述4、堆參數調優入門5、JVM 的配置和優化6、Tomcat 的配置和優化


熟悉 JVM 架構與 GC 垃圾回收機制以及相應的 JVM 調優,有過在 Linux 系統下的調優經驗。

淘寶的周志明《深入理解 Java 虛擬機》中說 JVM 的優化,其中 99% 優化的是堆,1% 優化的是方法區。

內地女歌手照片--李嘉欣,貼在桌面上。

1、JVM 位置

JVM 是運行在操作系統之上的,它與硬件沒有直接的交互

2、JVM 體系結構概覽

詳解如下:

類裝載器 Class Loader
  負責加載 class 文件,class 文件在文件開頭有特定的文件標示,並且 Class Loader 只負責 class 文件的加載,至於它是否可以運行,則由 Execution Engine 決定。

虛擬機自帶的加載器
  啓動類加載器(Bootstrap)C++
  擴展類加載器(Extension)Java
  應用程序類加載器(AppClassLoader)Java
  也叫系統類加載器,加載當前應用的 classpath 的所有類

用戶自定義的加載器
  Java.lang.ClassLoader 的子類,用戶可以定製類的加載方式。
  Code 案例
  sun.misc.Launcher 它是一個 java 虛擬機的入口應用。

Execution Engine 執行引擎
  執行引擎負責解釋命令,提交操作系統執行。

Native Interface 本地接口
  本地接口的作用是融合不同的編程語言爲 Java 所用,它的初衷是融合 C/C++ 程序,Java 誕生的時候是 C/C++ 橫行的時候,要想立足,必須有調用 C/C++ 程序,於是就在內存中專門開闢了一塊區域處理標記爲 native 的代碼,它的具體做法是 Native Method Stack 中登記 native 方法,在 Execution Engine 執行時加載 native libraies。

  目前該方法使用的越來越少了,除非是與硬件有關的應用,比如通過 Java 程序驅動打印機或者 Java 系統管理生產設備,在企業級應用中已經比較少見。

  因爲現在的異構領域間的通信很發達,比如可以使用 Socket 通信,也可以使用 Web Service 等等,不多做介紹。

Native Method Stack 本地方法棧
  它的具體做法是 Native Method Stack 中登記 native 方法,在 Execution Engine 執行時加載本地方法庫。

PC Register 程序寄存器
  每個線程都有一個程序計數器,是線程私有的,就是一個指針,指向方法區中的方法字節碼(用來存儲指向下一條指令的地址,也即將要執行的指令代碼),由執行引擎讀取下一條指令,是一個非常小的內存空間,幾乎可以忽略不記。

  這塊內存區域很小,它是當前線程所執行的字節碼的行號指示器,字節碼解釋器通過改變這個計數器的值來選取下一條需要執行的字節碼指令。

  如果執行的是一個 Native 方法,那這個計數器是空的。

Method Area 方法區
  方法區是被所有線程共享,所有字段和方法字節碼,以及一些特殊方法如構造函數,接口代碼也在此定義。簡單說,所有定義的方法的信息都保存在該區域,此區屬於共享區間

  靜態變量 + 常量 + 類信息(構造方法/接口定義) + 運行時常量池 存在方法區中,但是實例變量存在堆內存中,和方法區無關

  方法區主要存放的是:構造方法 + 接口的代碼

Stack 棧是什麼
  棧也叫棧內存,主管 Java 程序的運行,是在線程創建時創建,它的生命期是跟隨線程的生命期,線程結束棧內存也就釋放,對於棧來說不存在垃圾回收問題,只要線程一結束該棧就 over,生命週期和線程一致,是線程私有的。8 種基本類型的變量 + 對象的引用變量 + 實例方法都是在函數的棧內存中分配。

棧存儲什麼?
棧幀中主要保存 3 類數據:
  本地變量(Local Variables):輸入參數和輸出參數以及方法內的變量。
  棧操作(Operand Stack):記錄出棧、入棧的操作。
  棧幀數據(Frame Data):包括類文件、方法等等。

棧運行原理
  棧中的數據都是以棧幀(Stack Frame)的格式存在,棧幀是一個內存區塊,是一個數據集,是一個有關方法(Method)和運行期數據的數據集,當一個方法 A 被調用時就產生了一個棧幀 F1,並被壓入到棧中,A 方法又調用了 B 方法,於是產生棧幀 F2 也被壓入棧,B 方法又調用了 C 方法,於是產生棧幀 F3 也被壓入棧,…… 執行完畢後,先彈出 F3 棧幀,再彈出 F2 棧幀,再彈出 F1 棧幀,……

  遵循 “先進後出”/“後進先出” 原則。

  每個方法執行的同時都會創建一個棧幀,用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息,每一個方法從調用直至執行完畢的過程,就對應着一個棧幀在虛擬機中入棧到出棧的過程。棧的大小和具體 JVM 的實現有關,通常在 256K~756K 之間。

  棧內存溢出異常:Exception in thread "main" java.lang.StackOverflowError

  棧管運行,堆管存儲。

三種 JVM
  1、Sun 公司的 HotSpot(Oracle 收購)
  2、BEA 公司的 JRockit(Oracle 收購)
  3、IBM 公司的 J9 VM

3、堆體系結構概述

JVM 優化的是哪裏?

Heap 堆
  一個 JVM 實例只存在一個堆內存,堆內存的大小是可以調節的。類加載器讀取了類文件後,需要把類、方法、常變量放到堆內存中,保存所有引用類型的真實信息,以方便執行器執行,堆內存分爲三部分:

  • Young Generation Space 新生區 Young/New
  • Tenure generation space 養老區 Old/Tenure
  • Permanent Space 永久區 Perm

Heap 堆(Java7 之前)
  一個 JVM 實例只存在一個堆內存,堆內存的大小是可以調節的。類加載器讀取了類文件後,需要把類、方法、常變量放到堆內存中,保存所有引用類型的真實信息,以方便執行器執行。
  堆內存邏輯上分爲三部分:新生 + 養老 + 永久

新生區
  新生區是類的誕生、成長、消亡的區域,一個類在這裏產生、應用、最後被垃圾回收器收集、結束生命。新生區又分爲兩部分:伊甸區(Eden space)和倖存者區(Survivor pace),所有的類都是在伊甸區被 new 出來的。倖存區有兩個:0 區(Survivor 0 space)和 1 區(Survivor 1 space)。當伊甸園的空間用完時,程序又需要創建對象,JVM 的垃圾回收器將對伊甸園區進行垃圾回收
(Minor GC),將伊甸園區中的不再被其他對象所引用的對象進行銷燬。然後將伊甸園中的剩餘對象移動到倖存 0 區。若倖存 0 區也滿了,再對該區進行垃圾回收,然後移動到 1 區。那如果
1 區也滿了呢?再移動到養老區。若養老區也滿了,那麼這個時候將產生 Major GCFull GC),進行養老區的內存清理。若養老區執行了 Full GC 之後發現依然無法進行對象的保存,就會產生 OOM 異常 “OutOfMemoryError”。

  如果出現 java.lang.OutOfMemoryError: Java heap space 異常,說明 Java 虛擬機的堆內存不夠。原因有二:
  (1)Java 虛擬機的堆內存設置不夠,可以通過參數 -Xms、-Xmx 來調整
  (2)代碼中創建了大量大對象,並且長時間不能被垃圾收集器收集(存在被引用)
  如何 new 一個大對象? 答:byte[] byteArray = new byte[1 * 1024 * 1024 * 7000];

養老區
  養老區用於保存從新生區篩選出來的 Java 對象,一般池對象都在這個區域活躍。

永久區
  永久存儲區是一個常駐內存區域,用於存放 JDK 自身所攜帶的 Class、Interface 的元數據,也就是說它存儲的是運行環境必須的類信息,被裝載進此區域的數據是不會被垃圾回收器回收掉的,關閉 JVM 纔會釋放此區域所佔用的內存。

  如果出現 java.lang.OutOfMemoryError: PermGen space,說明是 Java 虛擬機對永久代 Perm 內存設置不夠。一般出現這種情況,都是程序啓動需要加載大量的第三方 jar 包。例如:在一個 Tomcat 下部署了太多的應用。或者大量動態反射生成的類不斷被加載,最終導致 Perm 區被佔滿。

  Java 7 叫永久代,Java 8 叫元空間。

  實際而言,方法區(Method Area)和堆一樣,是各個線程共享的內存區域,它用於存儲虛擬機加載的:類信息+普通常量+靜態常量+編譯器編譯後的代碼等等,雖然 JVM 規範將方法區描述爲堆的一個邏輯部分,但它卻還有一個別名叫做 Non-Heap(非堆),目的就是要和堆分開。

  對於 HotSpot 虛擬機,很多開發者習慣將方法區稱之爲“永久代(Parmanent Gen)”,但嚴格本質上說兩者不同,或者說使用永久代來實現方法區而已,永久代是方法區(相當於是一個接口 interface)的一個實現jdk1.7 的版本中,已經將原本放在永久代的字符串常量池移走

jdk 1.6 方法區就是永久代。常量池在方法區中。
jdk 1.7 中 常量池放在了堆中。

RUNTIME CONSTANT POOL 運行時常量池
  常量池(Constant Pool)是方法區的一部分,Class 文件除了有類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池,常量池用於存放編譯期間生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。

熟悉三區結構後方可學習-JVM 垃圾收集

4、堆參數調優入門

JVM 垃圾收集(Java Garbage Collection)
以 JDK1.7 + HotSpot 爲例

以 JDK1.8 + HotSpot 爲例

堆內存調優簡介 01

堆內存調優簡介 02
發現默認的情況下分配的內存是總內存的“1 / 4”、而初始化的內存爲“1 / 64”


調整 VM 參數並打印出來:-Xms1024m -Xmx1024m -XX:+PrintGCDetails

堆內存調優簡介 03
java 7


java 8

堆內存調優簡介 04
調整 VM 參數並打印出來:-Xms8m -Xmx8m -XX:+PrintGCDetails
java 7


java 8

MAT(Eclipse Memory Analyzer Tool)


官網訪問地址:https://projects.eclipse.org/projects/tools.mat/downloads

安裝方式1:離線 jar 包方式
1)Eclipse Memory Analyzer Windows 64 位下載地址:http://www.eclipse.org/downloads/download.php?file=/mat/1.8.1/rcp/MemoryAnalyzer-1.8.1.20180910-win32.win32.x86_64.zip
2)解壓下載包:放到 eclipse 或 myeclipse 安裝目錄的 dropins 目錄下。
3)啓動 eclipse 或 myeclipse,打開 Window - > Perspective,看到 Memory Analyzer 證明安裝成功。

安裝方式2:聯網插件安裝方式
http://download.eclipse.org/mat/1.8.1/update-site/

使用 MAT 分析
  啓動 eclipse 或 myeclipse,打開 File - > Open heap dump,在彈出的對話框選擇生成的 dump文件,就可以看到 MAT 給出了overview page。

面試題

5、JVM 的配置和優化

JVM 複習

GC 是什麼
  頻繁收集 新生區,使用的算法是複製算法
  較少收集 老年區,使用的算法是
  基本不動 永久區 (jdk7)

GC 三大算法

GC 算法總體概述

複製算法:Minor GC(普通 GC)
新生代中使用的是 Minor GC(普通 GC),這種 GC 算法採用的是複製算法(Copying)
複製算法的原理如下圖所示:

Minor GC(普通 GC)會把 Eden 中的所有活的對象都移到 Survivor 區域中,如果 Survivor 區域中放不下,那麼剩下的活的對象就被移動到 Old Generation 中,也即一旦收集後,Eden 就變成空的了

複製算法的缺點:

標記清除算法/標記整理算法:Full GC 又叫 Major GC(全局 GC)
老年代一般是由標記清除或者是標記清除與標記整理的混合實現。

標記清除:Mark-Sweep
標記清除原理

標記清除算法的缺點:

標記整理:Mark-Compact
標記整理算法原理

標記整理算法的缺點:

小總結

面試題

6、Tomcat 的配置和優化


(1)點擊【參數配置】選項,Eclipse 中的 Tomcat 一般在默認情況下內存偏小,運行一會兒就會拋出內存溢出錯誤,需要在 Tomcat 的 VM arguments 中添加如下參數:-Xms128M -Xmx512M -XX:PermSize=512m -XX:MaxPermSize=1024m,具體大小根據自己的電腦硬件。最後點擊下面的 "OK" 按鈕保存配置。

(2)45秒和15秒分別是tomcat啓動和停止的超時時間,該長一些,防止工程較大啓動慢造成工程啓動不了。

(3)Eclipse默認將工程部署至eclipse的目錄中,目錄層次較深不易操作,這裏改到tomcat自己的部署目錄中。
注意:如果eclipse的tomcat已添加工程需要在eclipse中將tomcat下的工程全部移除後方可設置該項。

配置完成後,要點擊【保存】按鈕。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章