目錄介紹
-
01.Java對象的建立過程php
- 1.0 看下建立類加載過程
- 1.1 對象的建立
- 1.2 對象的內存佈局
-
02.Java內存區域java
- 2.0 運行時數據區域
- 2.1 程序計數器
- 2.2 虛擬機棧
- 2.3 本地方法棧
- 2.4 Java堆
- 2.5 方法區
- 2.6 運行時常量池
- 2.7 直接內存
-
03.Java對象的訪問定位方式git
-
04.Java對象銷燬分析程序員
- 4.1 JVM內存分配與回收
- 4.2 判斷對象是否死亡
- 4.3 不可達的對象並不是「非死不可」
- 4.4 如何判斷一個常量是廢棄常量
- 4.5 如何判斷一個類是無用的類
- 4.6 GC回收算法詳解
-
05.String類和常量池github
- 5.1 String對象的兩種建立方式
- 5.2 String類型的常量池
好消息
- 博客筆記大彙總【16年3月到至今】,包括Java基礎及深刻知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug彙總,固然也在工做之餘收集了大量的面試題,長期更新維護而且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計47篇[近20萬字],轉載請註明出處,謝謝!
- 連接地址:https://github.com/yangchong2...
- 若是以爲好,能夠star一下,謝謝!固然也歡迎提出建議,萬事起於忽微,量變引發質變!
問題思考答疑
- 說一下建立一個對象,類的加載過程。類信息,常量,變量,方法分別放到內存中哪裏?
- 對於運行時數據區域,哪些是私有的,哪些是共享的,爲何要這樣設計?
- 程序計數器會出現OOM嗎?它的生命週期是怎麼樣的?
- 本地方法棧和Java虛擬機棧有什麼區別?本地方法棧在什麼狀況下會形成OOM?
- java堆主要是作什麼做用的?
- 什麼是類的加載檢查,主要檢查什麼,如何檢查呢?
- Java對象訪問定位方式有哪些?主要有什麼區別?爲何說使用指針效率更高?
- String類能夠new嗎?直接new和賦值的內容有什麼區別,分別放在內存中什麼地方?
- 如何判斷對象是否死亡(兩種方法)。若是有不一樣方法,那麼之間有什麼區別?
- 簡單的介紹一下強引用、軟引用、弱引用、虛引用(虛引用與軟引用和弱引用的區別、使用軟引用能帶來的好處)。
- 如何判斷一個常量是廢棄常量,如何判斷一個類是無用的類?
- 垃圾收集有哪些算法,各自的特色?常見的垃圾回收器有那些?
- HotSpot爲何要分爲新生代和老年代?
- 介紹一下CMS,G1收集器。Minor Gc和Full GC 有什麼不一樣呢?
01.Java對象的建立過程
1.1 看下建立類加載過程
-
Person p = new Person()請寫一下類的加載過程?面試
1).由於new用到了Person.class,因此會先找到Person.class文件,並加載到內存中;
2).執行該類中的static代碼塊,若是有的話,給Person.class類進行初始化;
3).在堆內存中開闢空間分配內存地址;
4).在堆內存中創建對象的特有屬性,並進行默認初始化;
5).對屬性進行顯示初始化;
6).對對象進行構造代碼塊初始化;
7).對對象進行與之對應的構造函數進行初始化;
8).將內存地址付給棧內存中的p變量
1.1 對象的建立
1.2 對象的內存佈局
- 在 Hotspot 虛擬機中,對象在內存中的佈局能夠分爲3快區域:對象頭、實例數據和對齊填充。
- Hotspot虛擬機的對象頭包括兩部分信息,第一部分用於存儲對象自身的自身運行時數據(哈希嗎、GC分代年齡、鎖狀態標誌等等),另外一部分是類型指針,即對象指向它的類元數據的指針,虛擬機經過這個指針來肯定這個對象是那個類的實例。
- 實例數據部分是對象真正存儲的有效信息,也是在程序中所定義的各類類型的字段內容。
- 對齊填充部分不是必然存在的,也沒有什麼特別的含義,僅僅起佔位做用。
- 由於Hotspot虛擬機的自動內存管理系統要求對象起始地址必須是8字節的整數倍,換句話說就是對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的倍數(1倍或2倍),所以,當對象實例數據部分沒有對齊時,就須要經過對齊填充來補全。
02.Java內存區域
2.0 運行時數據區域
2.1 程序計數器
- 程序計數器:是一個數據結構,用於保存當前正常執行的程序的內存地址。Java虛擬機的多線程就是經過線程輪流切換並分配處理器時間來實現的,爲了線程切換後能恢復到正確的位置,每條線程都須要一個獨立的程序計數器,互不影響,該區域爲「線程私有」。
- 程序計數器是一塊較小的內存空間,能夠看做是當前線程所執行的字節碼的行號指示器。字節碼解釋器工做時經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等功能都須要依賴這個計數器來完。
-
程序計數器主要有兩個做用:
- 1.字節碼解釋器經過改變程序計數器來依次讀取指令,從而實現代碼的流程控制,如:順序執行、選擇、循環、異常處理。
- 2.在多線程的狀況下,程序計數器用於記錄當前線程執行的位置,從而當線程被切換回來的時候可以知道該線程上次運行到哪兒。
- 注意:程序計數器是惟一一個不會出現OutOfMemoryError的內存區域,它的生命週期隨着線程的建立而建立,隨着線程的結束而死亡。
2.2 虛擬機棧
2.3 本地方法棧
- 本地方法棧:跟虛擬機棧很像, 虛擬機棧爲虛擬機執行 Java 方法 (也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的 Native 方法服務。 在 HotSpot 虛擬機中和 Java 虛擬機棧合二爲一。
- 本地方法被執行的時候,在本地方法棧也會建立一個棧幀,用於存放該本地方法的局部變量表、操做數棧、動態連接、出口信息。
- 方法執行完畢後相應的棧幀也會出棧並釋放內存空間,也會出現 StackOverFlowError 和 OutOfMemoryError 兩種異常。
2.4 Java堆
2.5 方法區
2.6 運行時常量池
2.7 直接內存
- 直接內存並非虛擬機運行時數據區的一部分,也不是虛擬機規範中定義的內存區域,可是這部份內存也被頻繁地使用。並且也可能致使OutOfMemoryError異常出現。
- JDK1.4中新加入的 NIO(New Input/Output) 類,引入了一種基於通道(Channel) 與緩存區(Buffer) 的 I/O 方式,它能夠直接使用Native函數庫直接分配堆外內存,而後經過一個存儲在 Java 堆中的 DirectByteBuffer 對象做爲這塊內存的引用進行操做。這樣就能在一些場景中顯著提升性能,由於避免了在 Java 堆和 Native 堆之間來回複製數據。
- 本機直接內存的分配不會收到 Java 堆的限制,可是,既然是內存就會受到本機總內存大小以及處理器尋址空間的限制。
03.Java對象的訪問定位方式
- 創建對象就是爲了使用對象,咱們的Java程序經過棧上的 reference 數據來操做堆上的具體對象。對象的訪問方式有虛擬機實現而定
-
目前主流的訪問方式有
-
這兩種對象訪問方式各有優點。
- 使用句柄來訪問的最大好處是 reference 中存儲的是穩定的句柄地址,在對象被移動時只會改變句柄中的實例數據指針,而 reference 自己不須要修改。
- 使用直接指針訪問方式最大的好處就是速度快,它節省了一次指針定位的時間開銷。
3.1 句柄
- 若是使用句柄的話,那麼Java堆中將會劃分出一塊內存來做爲句柄池,reference 中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息;

3.2 直接指針
- 若是使用直接指針訪問,那麼 Java 堆對像的佈局中就必須考慮如何放置訪問類型數據的相關信息,而reference 中存儲的直接就是對象的地址。

04.Java對象銷燬分析
4.1 JVM內存分配與回收
4.2 判斷對象是否死亡
4.2.1 引用計數法
-
給對象中添加一個引用計數器,每當有一個地方引用它,計數器就加1;當引用失效,計數器就減1;任什麼時候候計數器爲0的對象就是不可能再被使用的。
- 這個方法實現簡單,效率高,可是目前主流的虛擬機中並無選擇這個算法來管理內存,其最主要的緣由是它很難解決對象之間相互循環引用的問題。
- 所謂對象之間的相互引用問題,以下面代碼所示:除了對象objA和objB相互引用着對方以外,這兩個對象之間再無任何引用。可是他們由於互相引用對方,致使它們的引用計數器都不爲0,因而引用計數算法沒法通知 GC 回收器回收他們。
public class Test {
Object instance = null;
public static void main(String[] args) {
Test objA = new Test();
Test objB = new Test();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
}
}
4.2.2 可達性分析算法
4.2.3 再談引用
- 不管是經過引用計數法判斷對象引用數量,仍是經過可達性分析法判斷對象的引用鏈是否可達,斷定對象的存活都與「引用」有關。
- JDK1.2之後,Java對引用的概念進行了擴充,將引用分爲強引用、軟引用、弱引用、虛引用四種(引用強度逐漸減弱)
- 關於四種引用以及源代碼分析,能夠看個人這篇文章:https://blog.csdn.net/m0_3770...
4.3 不可達的對象並不是「非死不可」
- 即便在可達性分析法中不可達的對象,也並不是是「非死不可」的,這時候它們暫時處於「緩刑階段」,要真正宣告一個對象死亡,至少要經歷兩次標記過程;可達性分析法中不可達的對象被第一次標記而且進行一次篩選,篩選的條件是此對象是否有必要執行 finalize 方法。當對象沒有覆蓋 finalize 方法,或 finalize 方法已經被虛擬機調用過期,虛擬機將這兩種狀況視爲沒有必要執行。
- 被斷定爲須要執行的對象將會被放在一個隊列中進行第二次標記,除非這個對象與引用鏈上的任何一個對象創建關聯,不然就會被真的回收。
4.4 如何判斷一個常量是廢棄常量
4.5 如何判斷一個類是無用的類
4.6 GC回收算法詳解
05.String類和常量池
5.1 String對象的兩種建立方式
5.2 String類型的常量池
String s1 = new String("yc");
String s2 = s1.intern();
String s3 = "yc";
System.out.println(s2);//yc
System.out.println(s1 == s2);//false,由於一個是堆內存中的String對象一個是常量池中的String對象,
System.out.println(s3 == s2);//true,由於兩個都是常量池中的String對
關於其餘內容介紹
01.關於博客彙總連接
02.關於個人博客