對於C語言開發的程序員來講,在內存管理方面,必須負責每個對象的生命週期,從有到無。java
對於Java程序員你來講,在虛擬機內存管理的幫助下,不須要爲每一個new對象都匹配free操做,內存泄露和內存溢出等問題也不太容易出現,不過也正是由於把內存管理交給了虛擬機,一旦運行中的程序出現了內存泄露問題,給排查過程形成很大困難。因此只有理解了Java虛擬機的運行機制,纔可以指揮若定於各類代碼。本文以HotSpot爲例說說虛擬機的那些事。程序員
JAVA虛擬機把管理的內存劃分爲幾個不一樣的數據區。面試
Java堆是被全部線程共享的一塊內存區域,主要用於存放對象實例,Java虛擬機規範中有這樣一段描述:全部的對象實例和數據都要在堆上進行分配。爲對象分配內存就是把一塊大小肯定的內存從堆內存中劃分出來,一般有兩種方法實現:數組
1 、指針碰撞法性能優化
假設Java堆中內存時完整的,已分配的內存和空閒內存分別在不一樣的一側,經過一個指針做爲分界點,須要分配內存時,僅僅須要把指針往空閒的一端移動與對象大小相等的距離。數據結構
二、空閒列表法多線程
事實上,Java堆的內存並非完整的,已分配的內存和空閒內存相互交錯,JVM經過維護一個列表,記錄可用的內存塊信息,當分配操做發生時,從列表中找到一個足夠大的內存塊分配給對象實例,並更新列表上的記錄。架構
對象建立是一個很是頻繁的行爲,進行堆內存分配時還須要考慮多線程併發問題,可能出現正在給對象A分配內存,指針或記錄還未更新,對象B又同時分配到原來的內存,解決這個問題有兩種方案:併發
一、採用CAS保證數據更新操做的原子性;分佈式
二、把內存分配的行爲按照線程進行劃分,在不一樣的空間中進行,每一個線程在Java堆中預先分配一個內存塊,稱爲本地線程分配緩衝(Thread Local Allocation Buffer, TLAB);
Java棧是線程私有的,每一個線程對應一個Java棧,每一個線程在執行一個方法時會建立一個對應的棧幀(Stack Frame),棧幀負責存儲局部變量變量表、操做數棧、動態連接和方法返回地址等信息。每一個方法的調用過程,至關於棧幀在Java棧的入棧和出棧過程。
局部變量表 用於存放方法參數和方法內部定義的局部變量,其大小在代碼編譯期間已經肯定,在方法運行期間不會改變。局部變量表以變量槽(Slot)爲最小存儲單位,每一個Slot可以存放一個boolean、byte、char、shot、int、float、reference和returnAddress類型的32位數據,對於64位的數據類型long和double,虛擬機會以高位對齊的方式爲其分配兩個連續的Slot空間。
在方法執行時,若是是實例方法,即非static方法,局部變量表中第0位Slot默認存放對象實例的引用,在方法中能夠經過關鍵字 this 進行訪問,方法參數按照參數列表順序,從第1位Slot開始分配,方法內部變量則按照定義順序進行分配其他的Slot。
對應的局部變量表以下:
使用 javap -c 命令查看方法calc的字節碼
其中iload_1和iload_2分別從局部變量表中的第1位和第2位中加載數據。
方法區和Java堆同樣,是全部線程共享的內存區域,用於存放已被虛擬機加載的類信息、常量、靜態變量和即時編譯器編譯後的代碼等數據。
運行時常量池是方法區的一部分,用於存放編譯期間生成的各類字面常量和符號引用。
指令計數器是線程私有的,每一個線程都有獨立的指令計數器,計數器記錄着虛擬機正在執行的字節碼指令的地址,分支、循環、跳轉、異常處理和線程恢復等操做都依賴這個計數器完成。若是線程執行的是native方法,這個計數器則爲空。
對象在內存中佈局能夠分紅三塊區域:對象頭、實例數據和對齊填充。
一、對象頭
對象頭包括兩部分信息:運行時數據和類型指針,若是對象是一個數組,還須要一塊用於記錄數組長度的數據。
1.一、運行時數據包括哈希碼(HashCode)、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向鎖ID和偏向時間戳等,這部分數據在32位和64位虛擬機中的長度分別爲32bit和64bit,官方稱爲」Mark Word」。Mark Word被設計成非固定的數據結構,以實如今有限空間內保存儘量多的數據。
32位的虛擬機中,對象未被鎖定的狀態下,Mark Word的32bit中25bit存儲對象的HashCode、4bit存儲對象分代年齡、2bit存儲鎖標誌位、1bit固定爲0,具體以下:
其它狀態(輕量級鎖定、重量級鎖定、GC鎖定、可偏向鎖)下Mark Word的存儲內容以下:
1.二、對象頭的類型指針指向該對象的類元數據,虛擬機經過這個指針能夠肯定該對象是哪一個類的實例。
二、實例數據
實例數據就是在程序代碼中所定義的各類類型的字段,包括從父類繼承的,這部分的存儲順序會受到虛擬機分配策略和字段在源碼中定義順序的影響。
三、對齊填充
因爲HotSpot的自動內存管理要求對象的起始地址必須是8字節的整數倍,即對象的大小必須是8字節的整數倍,對象頭的數據正好是8的整數倍,因此當實例數據不夠8字節整數倍時,須要經過對齊填充進行補全。
在互聯網公司面試中,架構的底層必定是面試官會問到的問題,針對面試官通常會提到的問題,我錄製了一些分佈式,微服務,性能優化等技術點底層原理的錄像視頻,加羣: 478030634 能夠免費獲取這些錄像,裏面還有些分佈式,微服務,性能優化,Spring,MyBatis的等源碼知識點的錄像視頻。這些視頻都是我找一些資深架構師朋友一塊兒錄製出來的,這些視頻幫助如下幾類程序員:
1.對如今的薪資不滿,想要跳槽,卻對本身的技術沒有信心,不知道如何面對面試官。
2.想從傳統行業轉行到互聯網行業,但沒有接觸過互聯網技術。
3.工做1 - 5年須要提高本身的核心競爭力,但學習沒有系統化,不知道本身接下來要學什麼纔是正確的,踩坑後又不知道找誰,百度後依然不知因此然。
4.工做5 - 10年沒法突破技術瓶頸(運用過不少技術,在公司一直寫着業務代碼,卻依然不懂底層實現原理)
若是你如今正處於我上述所說的幾個階段能夠加下個人羣來學習。並且我也可以提供一些面試指導,職業規劃等建議。