JVM之內存管理(一)

部分內容來源:JavaGuide+二哥Java


圖解JVM內存結構


內存管理快速復習

棧幀:局部變量表,動態鏈接(符號引用轉為真實引用),操作數棧(存儲中間結算結果),方法返回地址

運行時常量池:常量池表,符號引用,字面量

對象創建過程:類加載檢查(類沒有加載就進行類加載)+分配內存+初始化零值+設置對象頭+執行對象初始化方法

類加載過程:

  1. 加載:通過類的全限定名獲取該類的二進制字節流,存到類常量池,內存中生成Class類對象
  2. 連接:
    1. 驗證:驗證Class二進制字節流合規(例如驗證魔數和版本號)
    2. 準備:為類對象分配內存
    3. 解析:符號引用轉為直接引用
  1. 初始化:執行初始化方法

內存分配:指針碰撞(CAS重試)+空閑列表

內存分配失敗:CAS配上重試機制+TLAB為每個線程預先在Eden區分配一塊內存

對象:對象頭(運行時數據+類型指針,GC年齡,Hash碼)+實例數據

對象訪問定位:使用句柄(間接訪問)+直接指針訪問

JVM堆內存分區:新生代(Eden+S1+S2)+老年代

對象什么時候會進入老年代:長期存活的對象,大對象,動態年齡判斷分配擔保機制

逃逸分析:在棧內為對象分配內存

Stop The World :停止所有用戶線程

Oop Map:記錄了對象內部所有引用字段(指針)的位置

安全點:可以暫停所有線程執行特定操作的位置

常量池包括:

類常量池

運行時常量池

字符串常量池

JDK1.6:常量池在永久代

JDK1.7:運行時常量池+類常量池在永久代,字符串常量池在堆

JDK1.8:運行時常量池+類常量池在元空間,字符串常量池在堆


引用類型有哪些?有什么區別?

強引用指的就是代碼中普遍存在的賦值方式,比如 A a = new A () 這種。強引用關聯的對象,永遠不會被 GC 回收

軟引用可以用 SoftReference 來描述,指的是那些有用但是不是必須要的對象

系統在發生內存溢出前會對這類引用的對象進行回收

弱引用可以用 WeakReference 來描述,他的強度比軟引用更低一點

弱引用的對象下一次 GC 的時候一定會被回收,而不管內存是否足夠

虛引用也被稱作幻影引用,是最弱的引用關系,可以用 PhantomReference 來描述,他必須和 ReferenceQueue 一起使用,同樣的當發生 GC 的時候,虛引用也會被回收

可以用虛引用來管理堆外內存


說一下弱引用?舉例子在哪里可以引用?

Java 中的弱引用是一種引用類型,它不會阻止一個對象被垃圾回收


在 Java 中,弱引用是通過 Java.lang.ref.WeakReference 類實現的

弱引用的一個主要用途是創建非強制性的對象引用,這些引用可以在內存壓力大時被垃圾回收器清理,從而避免內存泄露


弱引用的使用場景:

  • 緩存系統:弱引用常用于實現緩存,特別是當希望緩存項能夠在內存壓力下自動釋放時。如果緩存的大小不受控制,可能會導致內存溢出。使用弱引用來維護緩存,可以讓 JVM 在需要更多內存時自動清理這些緩存對象。
  • 對象池:在對象池中,弱引用可以用來管理那些暫時不使用的對象。當對象不再被強引用時,它們可以被垃圾回收,釋放內存。
  • 避免內存泄露:當一個對象不應該被長期引用時,使用弱引用可以防止該對象被意外地保留,從而避免潛在的內存泄露

說一下你對內存泄露和內存溢出的了解

什么是內存泄露:

內存泄漏是指程序在運行過程中不再使用的對象仍然被引用而無法被垃圾收集器回收,從而導致可用內存逐漸減少

雖然在 Java 中,垃圾回收機制會自動回收不再使用的對象,但如果有對象仍被不再使用的引用持有,垃圾收集器無法回收這些內存,最終可能導致程序的內存使用不斷增加


內存泄露常見原因:

  • 靜態集合:使用靜態數據結構(如 HashMap 或 ArrayList)存儲對象,且未清理。
  • 事件監聽:未取消對事件源的監聽,導致對象持續被引用。
  • 線程沒被回收:未停止的線程可能持有對象引用,無法被回收。

內存溢出:

內存溢出是指 Java 虛擬機(JVM)在申請內存時,無法找到足夠的內存,最終引發 OutOfMemoryError 。這通常發生在堆內存不足以存放新創建的對象時


內存溢出常見原因:

  • 大量對象創建:程序中不斷創建大量對象,超出 JVM 堆的限制。
  • 持久引用:大型數據結構(如緩存、集合等)長時間持有對象引用,導致內存累積。
  • 遞歸調用:深度遞歸導致棧溢出

JVM的內存泄露有幾種溢出情況?

堆內存溢出:當出現 Java.lang.OutOfMemoryError:Java heap space 異常時,就是堆內存溢出了。原因是代碼中可能存在大對象分配,或者發生了內存泄露,導致在多次 GC 之后,還是無法找到一塊足夠大的內存容納當前對象

棧溢出:如果我們寫一段程序不斷的進行遞歸調用,而且沒有退出條件,就會導致不斷地進行壓棧。類似這種情況,JVM 實際會拋出 StackOverFlowError;當然,如果 JVM 試圖去擴展棧空間的時候失敗,則會拋出 OutOfMemoryError

元空間溢出:元空間的溢出,系統會拋出 Java.lang.OutOfMemoryError: Metaspace。出現這個異常的問題的原因是系統的代碼非常多或引用的第三方包非常多或者通過動態代碼生成類加載等方法,導致元空間的內存占用很大

直接內存內存溢出:在使用 ByteBuffer 中的 allocateDirect () 的時候會用到,很多 JavaNIO (像 netty) 的框架中被封裝為其他的方法,出現該問題時會拋出 Java.lang.OutOfMemoryError: Direct buffer memory 異常


棧中存的是指針還是對象?

在 JVM 內存模型中,棧(Stack)主要用于管理線程的局部變量和方法調用的上下文

而堆(Heap)則是用于存儲所有類的實例和數組


當我們在棧中討論 “存儲” 時,實際上指的是存儲基本類型的數據(如 int, double 等)和對象的引用,而不是對象本身。


這里的關鍵點是,棧中存儲的不是對象,而是對象的引用

也就是說,當你在方法中聲明一個對象,比如 MyObject obj = new MyObject ();,

這里的 obj 實際上是一個存儲在棧上的引用,指向堆中實際的對象實例

這個引用是一個固定大小的數據(例如在 64 位系統上是 8 字節),它指向堆中分配給對象的內存區域


說一下程序計數器的作用?為什么程序計數器是私有的?

Java 程序是支持多線程一起運行的,多個線程一起運行的時候 cpu 會有一個調動器組件給它們分配時間片,比如說會給線程 1 分給一個時間片,它在時間片內如果它的代碼沒有執行完,它就會把線程 1 的狀態執行一個暫存,切換到線程 2 去,執行線程 2 的代碼,等線程 2 的代碼執行到了一定程度,線程 2 的時間片用完了,再切換回來,再繼續執行線程 1 剩余部分的代碼


我們考慮一下,如果在線程切換的過程中,下一條指令執行到哪里了,是不是還是會用到我們的程序計數器啊

沒個線程都有自己的程序計數器,因為它們各自執行的代碼的指令地址是不一樣的呀,所以每個線程都應該有自己的程序計數器


說一下方法區中方法的執行過程

當程序中通過對象或類直接調用某個方法時,主要包括以下幾個步驟:

解析方法調用:JVM 會根據方法的符號引用找到實際的方法地址(如果之前沒有解析過的話)

棧幀創建:在調用一個方法前,JVM 會在當前線程的 Java 虛擬機棧中為該方法分配一個新的棧幀,用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息

執行方法:執行方法內的字節碼指令,涉及的操作可能包括局部變量的讀寫、操作數棧的操作、跳轉控制、對象創建、方法調用等。

返回處理:方法執行完畢后,可能會返回一個結果給調用者,并清理當前棧幀,恢復調用者的執行環境


JVM內存中的棧和堆有什么區別?

用途

棧主要用于存儲局部變量、方法調用的參數、方法返回地址以及一些臨時數據。每當一個方法被調用,一個棧幀(stack frame)就會在棧中創建,用于存儲該方法的信息,當方法執行完畢,棧幀也會被移除

堆用于存儲對象的實例(包括類的實例和數組)。當你使用 new 關鍵字創建一個對象時,對象的實例就會在堆上分配空間


生命周期

棧中的數據具有確定的生命周期,當一個方法調用結束時,其對應的棧幀就會被銷毀,棧中存儲的局部變量也會隨之消失

堆中的對象生命周期不確定,對象會在垃圾回收機制(Garbage Collection, GC)檢測到對象不再被引用時才被回收


存取速度

棧的存取速度通常比堆快,因為棧遵循先進后出(LIFO, Last In First Out)的原則,操作簡單快速

堆的存取速度相對較慢,因為對象在堆上的分配和回收需要更多的時間,而且垃圾回收機制的運行也會影響性能


存儲空間

棧的空間相對較小,且固定,由操作系統管理

當棧溢出時,通常是因為遞歸過深或局部變量過大

堆的空間較大,動態擴展,由 JVM 管理

堆溢出通常是由于創建了太多的大對象或未能及時回收不再使用的對象


可見性

棧中的數據對線程是私有的,每個線程有自己的棧空間。堆中的數據對線程是共享的,所有線程都可以訪問堆上的對象


static修飾的類型

未被static修飾的基本類型:基本類型的變量(局部變量)存放在棧中,而不是堆中。例如int num = 10;,變量num是在方法執行時在棧中開辟空間存儲的。基本類型的成員變量存放在堆中(當所屬對象在堆中時) 。

static修飾的基本類型:被static修飾的基本類型(靜態變量)存放在方法區(在 JDK 8 及之后,方法區的實現是元空間),而不是棧中。靜態變量屬于類,在類加載時就會分配空間并初始化,存儲在方法區供類的所有對象共享。

包裝類型:包裝類型屬于對象類型,其對象實例確實幾乎都存在堆中,但包裝類型的對象在某些場景下會有緩存機制。例如Integer-128127之間的值會被緩存,當創建這個范圍內的Integer對象時,不會在堆中重新創建,而是直接引用緩存中的對象

此外,部分包裝類(如IntegerShortByteCharacterLong)存在對象緩存機制。Integer為例,在創建-128127之間的Integer對象時,不會在堆中重新創建,而是直接引用方法區中緩存的對象;超出這個范圍才會在堆中創建新對象


線程的內部有什么?

程序計數器

本機方法棧

Java虛擬機棧


說一下JVM棧的內部組成

JVM棧的內部組成

Java虛擬機棧是線程私有的
它的生命周期和線程相同
除了Native方法是調用本地方法棧實現,其他的所有方法的調用都是通過Java虛擬機棧來實現的
Java虛擬機棧的內部是由棧幀組成
方法調用的數據需要通過棧進行傳遞,每一次方法調用都會有一個對應的棧幀被壓入棧中,每一個方法調用結束后,都會有一個棧幀被彈出


Java虛擬機棧的內部是由一個又一個的棧幀組成
棧幀內部:局部變量表、操作數棧、動態鏈接、方法返回地址
?


說一下棧幀的內部

局部變量表

存放了數據類型,對象引用


操作數棧

主要作為方法調用的中轉站使用,用于存放方法執行過程中產生的中間計算結果
另外,計算過程中產生的臨時變量也會放在操作數棧中

動態鏈接


場景:主要服務一個方法需要調用其他方法的場景
Class 文件的常量池里保存有大量的符號引用比如方法引用的符號引用。
當一個方法要調用其他方法,需要將常量池中指向方法的符號引用轉化為其在內存地址中的直接引用。動態鏈接的作用就是為了將符號引用轉換為調用方法的直接引用


方法返回地址

就是我們方法結束后的返回地址


說一下棧幀內部有啥?

局部變量表

操作數棧

動態鏈接

方法返回地址


說一下JVM棧會出現的問題

tackOverFlowError錯誤:棧幀過多爆了

函數循環調用過多

我們這個線程遞歸調用的時候,我們會往棧里面壓入棧幀,如果壓入的棧幀過多,就會爆出

Java方法的兩種返回方式

一:Returen正常返回

二:拋出異常


OutOfMemoryError:內存空間不夠爆了

虛擬機動態擴展棧時,無法申請到足夠的內存空間


什么是本地方法棧

為本地方法服務

(也就是和我們的操作系統有關,我們的操作系統的方法)


說一下JVM的內存區域

JVM 內存區域最粗略的劃分可以分為

當然,按照虛擬機規范,可以劃分為以下?個區域:

JVM 內存分為線程私有區線程共享區

線程共享區:方法區和堆

線程隔離的數據區: 虛擬機棧 、本地方法棧 和 程序計數器

1)程序計數器

程序計數器(Program Counter Register)也被稱為 PC 寄存器,是?塊較?的內存空間。

它可以看作是當前線程所執?的字節碼的?號指示器。

2Java 虛擬機棧

Java 虛擬機棧(Java Virtual Machine Stack)也是線程私有的,它的?命周期與線程相同。

Java 虛擬機棧描述的是 Java ?法執?的線程內存模型:?法執?時,JVM 會同步創建?個棧幀,?來存儲局部變量表、操作數棧、動態連接等。

3)本地方法棧

本地?法棧(Native Method Stacks)與虛擬機棧所發揮的作?是?常相似的,其區別只是虛擬機棧為虛擬機執?

Java ?法(也就是字節碼)服務,?本地?法棧則是為虛擬機使?到的本地(Native)?法服務。

Java 虛擬機規范允許本地?法棧被實現成固定??的或者是根據計算動態擴展和收縮的。

4Java

對于 Java 應?程序來說,Java 堆(Java Heap)是虛擬機所管理的內存中最?的?塊。Java 堆是被所有線程共享

的?塊內存區域,在虛擬機啟動時創建。此內存區域的唯??的就是存放對象實例,Java ?“幾乎”所有的對象實例

都在這?分配內存。Java 堆是垃圾收集器管理的內存區域,因此?些資料中它也被稱作“GC 堆”(Garbage Collected Heap,)。從回

收內存的?度看,由于現代垃圾收集器?部分都是基于分代收集理論設計的,所以 Java 堆中經常會出現 新?代 、?年代 、 Eden空間 、 From Survivor空間 、 To Survivor空間 等名詞,需要注意的是這種劃分只是根據垃圾回收機制來進?的劃分,不是 Java 虛擬機規范本身制定的

5)方法區

?法區是?較特別的?塊區域,和堆類似,它也是各個線程共享的內存區域,?于存儲已被虛擬機加載的類型信息、常量、靜態變量、即時編譯器編譯后的代碼緩存等數據

它特別在 Java 虛擬機規范對它的約束?常寬松,所以?法區的具體實現歷經了許多變遷,例如 jdk1.7 之前使?永久代作為?法區的實現


JVM的堆是用來干嘛的

Java 虛擬機所管理的內存中最大的一塊

Java 堆是所有線程共享的一塊內存區域,在虛擬機啟動時創建

此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例以及數組都在這里分配內存


什么是逃逸分析

jdk1.7之后,已經默認開啟逃逸分析

也就是某些方法中的對象引用沒有被返回或者未被外面使用,那么就可以直接在棧上分配內存

也就是我們不用在堆給這個對象分配內存,我們在棧上給這個對象分內存就可以了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82291.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82291.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82291.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

無線射頻模塊如何通過CE RED認證?關鍵規范與準備策略詳解

隨著無線通信設備在歐洲市場的廣泛應用,CE RED認證已成為模塊類產品進入歐盟的強制通行證。作為專注于LoRa模塊、對講模塊與FSK射頻模塊研發的技術企業,我們深知從設計、測試到量產,每一個環節都需緊扣合規底線。本文將圍繞CE RED認證核心要求…

Golang中集合相關的庫

一切編程語言的底層結構都是數組,其它復雜數據結構如Map, Stack,Heap和Queue都是基于數組建立起來的。 Go語言主流工具庫推薦(含常用數據結構實現) 以下是目前Go生態中最主流且活躍的工具庫,包含隊列、棧、優先級隊列…

ABAP 導入Excel形成內表

文章目錄 創建導入模板程序實現代碼代碼解析運行結果 創建導入模板 程序實現 代碼 *&---------------------------------------------------------------------* *& Report Z_EXCEL_UPLOAD_LHY *&--------------------------------------------------------------…

特殊配合力(SCA)作為全基因組關聯分析(GWAS)的表型,其生物學意義和應用價值

生物學意義 解析非加性遺傳效應 特殊配合力(SCA)主要反映特定親本組合的雜交優勢,由非加性遺傳效應(如顯性、超顯性、上位性)驅動。顯性效應涉及等位基因間的顯性互作,上位性效應則涉及不同位點間的基因互作。通過SCA-GWAS,可以定位調控這些非加性效應的關鍵基因組區域…

應急響應基礎模擬靶機-security1

PS:杰克創建在流量包(result.pcap)在根目錄下,請根據已有信息進行分析 1、攻擊者使用的端口掃描工具是? 2、通過流量及日志審計,攻擊者上傳shell的時訪問web使用IP地址是多少? 3、審計流量日志,攻擊者反彈shell的地址及端口? 4、攻擊者…

uniapp-商城-47-后臺 分類數據的生成(通過數據)

在第46章節中,我們為后臺數據創建了分類的數據表結構schema,使得可以通過后臺添加數據并保存,同時使用云函數進行數據庫數據的讀取。文章詳細介紹了如何通過前端代碼實現分類管理功能,包括獲取數據、添加、更新和刪除分類。主要代…

ClickHouse的基本操作說明

說明 文章內容包括數據庫管理、表操作及查詢等核心功能 創建數據庫 -- 默認引擎(Atomic) CREATE DATABASE IF NOT EXISTS test_db; -- MySQL引擎(映射外部MySQL數據庫) CREATE DATABASE mysql_db ENGINE MySQL(host:port, m…

Nacos源碼—7.Nacos升級gRPC分析四

大綱 5.服務變動時如何通知訂閱的客戶端 6.微服務實例信息如何同步集群節點 6.微服務實例信息如何同步集群節點 (1)服務端處理服務注冊時會發布一個ClientChangedEvent事件 (2)ClientChangedEvent事件的處理源碼 (3)集群節點處理數據同步請求的源碼 (1)服務端處理服務注冊…

《Overlapping Experiment Infrastructure: More, Better, Faster》論文閱讀筆記

文章目錄 1 背景2 三個核心概念3 Launch層:特性發布的專用機制4 流量分發策略和條件篩選4.1 四種流量分發類型4.2 條件篩選機制 5 工具鏈與監控體系6 實驗設計原則7 培訓參考與推薦 1 背景 谷歌(Google)以數據驅動著稱,幾乎所有可…

國芯思辰| 醫療AED可使用2通道24位模擬前端SC2946(ADS1292)

生物電信號監測技術在醫療健康行業中發展迅速,成為評估人體生理健康狀況的關鍵手段。心電(ECG)、腦電(EEG)和肌電(EMG)等信號,通過精密模擬前端芯片捕捉和處理,對醫療診斷…

數據結構【二叉搜索樹(BST)】

二叉搜索樹 1. 二叉搜索樹的概念2. 二叉搜索樹的性能分析3.二叉搜索樹的插入4. 二叉搜索樹的查找5. 二叉搜索樹的刪除6.二叉搜索樹的實現代碼7. 二叉搜索樹key和key/value使用場景7.1 key搜索場景:7.2 key/value搜索場景: 1. 二叉搜索樹的概念 二叉搜索…

RDMA高性能網絡通信實踐

RDMA高性能網絡通信實踐 一、背景介紹二、方法設計A.實現方案B.關鍵技術點 三、代碼及注釋四、注意事項 一、背景介紹 遠程直接內存訪問(RDMA)技術通過繞過操作系統內核和CPU直接訪問遠程內存,實現了超低延遲、高吞吐量的網絡通信。該技術廣…

ndarray數組掩碼操作,True和False獲取數據

#數組掩碼的表示方法 def testht05():a np.arange(1,10)mask [True,False,True,True,False,True,False,True,True]print(a[mask]) 另外的用法: #掩碼操作獲取子集 def testht06():a np.arange(1,100)print(a[a%3 0 & (a%7 0)] )b np.array([A,"B&qu…

索引工具explain

EXPLAIN 是 MySQL 中一個非常有用的工具,用于分析查詢的執行計劃。通過 EXPLAIN,你可以了解 MySQL 是如何執行查詢的,包括它如何使用索引、表的掃描方式等。這有助于優化查詢性能。以下是 EXPLAIN 輸出的各個字段的詳細解釋: 基本用法 EXPLAIN SELECT * FROM table_name …

Git回顧

參考視頻:【GeekHour】一小時Git教程 一句話定義:Git是一個免費開源的分布式版本控制系統。 版本控制系統可以分為兩種,1.集中式(SVN,CVS);2.分布式(git) git的工作區域和文件狀態…

python打卡day20

特征降維------特征組合(以SVD為例) 知識點回顧: 奇異值的應用: 特征降維:對高維數據減小計算量、可視化數據重構:比如重構信號、重構圖像(可以實現有損壓縮,k 越小壓縮率越高&#…

GuPPy-v1.2.0安裝與使用-生信工具52

GuPPy:Python中用于光纖光度數據分析的免費開源工具 01 背景 Basecalling 是將原始測序信號轉換為堿基序列的過程,通俗地說,就是“把堿基識別出來”。這一過程在不同代測序技術中各不相同: 一代測序是通過解析峰圖實現&#xff1…

47. 全排列 II

題目 給定一個可包含重復數字的序列 nums ,按任意順序 返回所有不重復的全排列。 示例 1: 輸入:nums [1,1,2] 輸出: [[1,1,2],[1,2,1],[2,1,1]] 示例 2: 輸入:nums [1,2,3] 輸出:[[1,2,3…

ERP系統操作流程,如何快速搭建流程體系

ERP流程圖,如何搭建和建立,ERP系統操作流程,ERP系統操作流程圖,采購流程,銷售流程,倉庫流程,MRP流程,PMC流程,財務流程,應收流程,應付流程&#x…

class path resource [] cannot be resolved to absolute file path

問題情景 java應用程序在IDE運行正常,打成jar包后執行卻發生異常: java.io.FileNotFoundException: class path resource [cert/sync_signer_pri_test.key] cannot be resolved to absolute file path because it does not reside in the file system:…