深入理解Java虛擬機 ch2 Java內存區域與內存溢出異常 讀書筆記

part2 自動內存管理機制

   本書的第一部分主要是介紹部分,正文主要從本部分開始。本部分的核心內容如標題所示:自動內存管理機制。引用一段作者的話:

Java與C++之間有一堵由動態內存分配和垃圾護手技術所圍成的“高牆”,牆外面的人想出去,牆裏面的人卻想出來。

  Java與C++最直觀的區別就是:Java的內存是自動分配和回收的。一方面,這爲內存管理提供了極大的便利性,不要像C++那樣對每一片內存都悉心呵護;另一方面,要是coder對JVM一無所知的話,編程時的靈活性就大大降低,當系統出現性能問題和故障時,就會一無所措,在設計方案時也往往無法具體問題具體分析。而本部分的目的就是講述Java自動內存管理機制,通過增加對JVM內存管理的瞭解,從而對性能優化故障處理等問題做到有的放矢。這樣,讓JVM做個貼心的大總管,管理所有的細節——內存分配和回收,自己只要負責控制大局——指定各區內存大小,指定垃圾回收器,制定服務器架構方案等即可。

  本部分由四個章節構成,其中第二章和第三章是重中之重。第四章講了JDK工具集:只要注意其中兩個可視化工具即可,之前的7個命令行工具已經集成在可視化工具中,這兩個工具可以在jdk的bin文件夾下找到。第五章講述了幾個調優案例的分析和作者本人對自己的Eclipse進行運行調優的過程。本人將對第二章和第三章進行整理,本篇博文主要關注第二章。

ch2 Java內存區域與內存溢出異常

   本章主要涉及三個話題:一是JVM運行時內存分區,二是HotSpot JVM在Java堆中進行對象創建、佈局和訪問全過程,三是內存溢出異常測試

一 JVM運行時內存分區

   JVM運行時內存分區主要分五塊兩種:一種是線程私有的,一種是各線程間共享的。

  線程私有的內存分爲三種:程序計數器,本地方法棧和Java虛擬機棧。

  程序計數器標誌當前線程所執行的字節碼程序的執行位置,用以保證程序按順序執行。需要注意的是:程序計數器只在Java方法中起作用,執行本地方法時計數器值爲空。本內存區不會拋出異常。

  Java虛擬機棧幀棧入棧和出棧的場所。棧幀是每個方法在執行時創建的用來存儲局部變量表、操作數棧、動態鏈接、方法出入等信息的。本內存區域可能拋出StackOverFlow異常OutOfMemory異常

  本地方法棧與Java虛擬機棧除了服務對象外,完全一致:Java虛擬機棧爲Java方法服務,本地方法棧爲Native方法服務。

  各線程共享的內存分爲兩種:Java堆和方法區。

  Java堆是JVM管理的內存中最大的一塊,被所有線程共享,在VM啓動時創建。此區域只用於存放對象實例,且幾乎所有的對象實例都存放於此(除了涉及JIT和逃逸分離技術,不懂。。)。Java堆是垃圾管理器管理的主要區域(還有就是下述的方法區),也被稱爲GC堆。Java堆本身也分很多區:包括新生代的Eden區和Survivor區,老年代,分配緩衝區等。Java堆可能拋出OutOfMemory異常

  方法區用以存儲已被虛擬機加載的類信息、常量、靜態變量和JIT編譯後的代碼等數據。HosSpot中以永久代的方式設計方法區。該區域內存回收的目標主要是對常量池的回收和對類型的卸裝。本區域會拋出OutOfMemory異常

  最後講下直接內存,也叫堆外內存。由名字可知,該內存與JVM無關。需要注意的是,直接內存也受總內存大小影響,在設計JVM內存的時候不要忘記直接內存的存在,否則可能會引起OutOfMemory異常。JDK中提供了DirectBuffe類,其對象在直接內存中存放。

二 HotSpot JVM在Java堆中進行對象創建、佈局和訪問

對象創建

  從虛擬機的角度看,當遇到new指令到對象創建完成需要經過四步:

  • 檢查參數能否在常量池中定位,並檢查對應的類是否被加載、解析和初始化;
  • 在類加載後,對新生對象分配內存。分配內存有指針碰撞法空閒列表法
  • 將分配到的內存空間都初始化爲零值;
  • 對對象進行必要的設置。

  此時,從VM的角度看,對象已經創建完畢;但從Java程序的角度看,對象創建剛開始。

對象內存佈局

   HotSpot虛擬機中,對象在內存中的佈局主要是對象頭和實例數據,還有就是用於對齊填充的部分。

  對象頭包括兩部分信息:第一部分用以存儲對象自身的運行時數據,其長度與VM位數相同。第二部分爲類型指針,用以指向對象的類元數據,虛擬機通過該指針來確定該對象對應的類。此外,若對象是一個Java數組,對象頭中還需要有一塊記錄數組長度的數據。

  實例數據是對象真正存儲的有效數據,其存儲順序與字段在類中的定義順序有關。另外,爲了優化,可能會將較窄的數據插入到前面的空隙中,減少對齊填充。

對象訪問定位

   Java程序通過棧上的reference數據來操作堆上的具體對象。該引用定位訪問堆中對象位置的方式由JVM自定,主要有句柄訪問直接指針兩種方法。其中,HotSpot中採用直接指針法。這部分具體內容可以看書,書上圖文並茂,講的很好。

三 內存溢出異常測試

  這裏需要說明的是,關於內存溢出異常分爲OutOfMemory異常StackOverflow異常。只有虛擬機棧和本地方法棧會產生StackOverflow異常;Java堆,方法區,虛擬機棧,本地方法棧和直接內存可能會產生OutOfMemory異常;程序計數區不會產生內存異常。

  可以根據以上說明自己設計異常測試或使用書中示例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章