JVM記憶體管理------JAVA語言的記憶體管理概述

來源:互聯網
上載者:User

標籤:lifo   簡單   情況   接下來   方法區   局部變數   自動   開始   本地   

引言     

     記憶體管理一直是JAVA語言自豪與驕傲的資本,它讓JAVA程式員基本上可以徹底忽略與記憶體管理相關的細節,只專註於商務邏輯。不過世界上不存在十全十美的好事,在帶來了便利的同時,也因此引入了很多令人抓狂的記憶體溢出和泄露的問題。

     可怕的事情還不只如此,有些使用其它語言開發的程式員,給JAVA程式員扣上了一個“不懂記憶體”的帽子,這著實有點讓人難以接受。畢竟JAVA當中沒有malloc和delete、沒有解構函式、沒有指標,剛開始接觸JAVA的程式員們又怎麼可能接觸記憶體這一部分呢,簡單來說在有限的空間做出無限的事情這就是JMM應該做的事情,我們盡量在寫代碼的時候按照記憶體回收的思路去寫代碼。我覺得這就是目的吧。

     不過事實儘管難以接受,但也確實有不少JAVA程式員對記憶體這部分可謂一竅不知,儘管掌握記憶體的相關知識,或許並不能給平時的開發帶來翻天覆地的變化和好處,不過它仍然會潛移默化的提高你的技術水準,這一點在瞭解完記憶體管理之後,相信各位就會深有體會了。

記憶體劃分

     談到記憶體這一詞彙,它是在程式運行時才有的資料存放區地區,而對於這一塊地區的劃分,各個虛擬機器有各自的劃分方式,不過它們都必須遵從JAVA虛擬機器的基本規範去實現。

     虛擬機器規範中,將記憶體劃分為六大部分,分別是PC寄存器、JAVA虛擬機器棧、JAVA堆、方法區、運行時常量池以及本地方法棧

JAVA虛擬機器規範與JAVA虛擬機器

     這裡還需要解釋一下JAVA虛擬機器規範和JAVA虛擬機器的區別,顧名思義,JAVA虛擬機器規範是一種對JAVA虛擬機器實現的規範要求,是由oracle制定的,而我們平時常說的JAVA虛擬機器一般是指的一種具體的JAVA虛擬機器規範的實現。比如我們最經常使用的JAVA虛擬機器hotspot,其實JAVA虛擬機器還有很多種實現,甚至如果你對JAVA虛擬機器規範有了深入的瞭解而且對此有興趣的話,可以寫一個自己的JAVA虛擬機器,當然這其中的難度不難想象。但是我不會。我也不需要去寫。

結構圖

記憶體地區詳解

     針對上面這張圖,記憶體就是指的矩形框當中運行期資料區這部分,下面簡單介紹一下各個部分的作用:

     1、PC寄存器(線程專屬):全稱是程式計數寄存器,它記載著每一個線程當前啟動並執行JAVA方法的地址,如果是當前執行的是本地方法,則程式計數器會是一個空地址。它的作用就是用來支援多線程,線程的阻塞、恢複、掛起等一系列操作,直觀的想象一下,要是沒有記住每個線程當前啟動並執行位置,又如何恢複呢。依據這一點,每一個線程都有一個PC寄存器,也就是說PC寄存器是線程專屬。

  2、JAVA虛擬機器棧(線程專屬)JAVA虛擬機器棧是在建立線程的同時建立的,用於儲存棧幀,JAVA虛擬機器棧也是線程專屬的

        棧幀:簡單點說,可以解釋為是一個方法運行時,臨時資料的儲存地區,具體點說,它裡麵包括了資料和部分的過程結果,與此同時,它又肩負著處理方法傳回值、動態連結以及異常指派的任務。棧幀是隨著方法的建立而建立,隨著方法的結束而銷毀,如果方法拋出異常,也算方法結束。然而在每一個棧幀中,都有著自己的局部變數表以及運算元棧以及對當前類的運行時常量池的引用。

        局部變數表:它是一個方法局部變數的列表,是在編譯時間期就寫入了class檔案當中。簡單的理解,可以將它理解為一個對象數組,而裡面按照索引0到length-1分別對應於每一個局部變數,特別的,如果是執行個體方法的局部變數表,第0個局部變數會是一個指向當前執行個體的引用,也就是this關鍵字,其餘的局部變數則從索引1開始。

        運算元棧它是一個後進先出(LIFO)棧,而它的長度也是在編譯時間期就寫入了class檔案當中,是固定的。它的作用就是提供位元組碼指令操作變數計算的空間,比如簡單的,對於int a=9這句話來說,就需要先將9壓入運算元棧,再將9賦給a這個變數。

3、JAVA堆(全域共用):這一部分是JAVA記憶體中最重要的一部分,之所以說是最重要的一部分,並不是因為它的重要性,而是指作為開發人員最應該關注的一部分。它隨著JAVA虛擬機器的啟動建立,儲存著所有對象執行個體以及數組對象,而且內建了“自動記憶體管理系統”,也就是我們常說的垃圾搜集器(GC)。JAVA堆中的記憶體釋放是不受開發人員控制的,完全由JAVA虛擬機器一手操辦。對於JAVA虛擬機器如何?垃圾搜集器,JAVA虛擬機器規範沒有明確的規定,也正因如此,我們平時使用的JAVA虛擬機器中提供了許多種垃圾搜集器,它們採用不同的演算法以及實現方式,已滿足多方面的效能需求。

     4、方法區(全域共用):方法區也是堆的一個組成部分,它主要儲存的是運行時常量池、欄位資訊、方法資訊、構造方法與普通函數的位元組碼內容以及一些特殊方法。它與JAVA堆的區別除了儲存的資訊與JAVA堆不一樣之外,最大的區別就是這一部分JAVA虛擬機器規範不強制要求實現自動記憶體管理系統(GC)。

     5、本地方法棧(線程專屬)本地方法棧是一個傳統的棧,它用來支援native方法的執行。如果JAVA虛擬機器是使用的其它語言實現指令集解譯器的時候,也會用到本地方法棧。如果前面這兩種都未發生,也就是說如果JAVA虛擬機器不依賴於本地方法棧,而且JAVA虛擬機器也不支援native方法,則不需要本地方法棧。而如果需要的話,則本地方法棧也是隨每一個線程的啟動而建立的。

     上面五個記憶體地區,除了PC寄存器之外,其餘四個一般情況下,都要求JAVA虛擬機器實現提供給客戶調節大小的參數,也就是我們常用的Xms、Xmx等等。

記憶體管理

     記憶體管理分為記憶體配置和記憶體釋放,看一下上面的五個記憶體地區,其實可以大致分為兩部分,一部分是全域共用,一部分是線程專屬

     對於線程專屬的這部分記憶體,都是隨著線程的啟動而建立,而當線程被銷毀時,記憶體也就隨之釋放。這一部分記憶體,不需要垃圾搜集器的管理,而是JAVA虛擬機器來主動管理,每當一個線程被建立的時候,JAVA虛擬機器就會為其分配相應的PC寄存器和JAVA虛擬機器棧,如果需要的話,還會有本地方法棧。相應的,當一個線程被銷毀的時候,JAVA虛擬機器也會將這個線程所佔有的記憶體全部釋放

     相對於線程專屬的那部分記憶體,全域共用的這部分記憶體更加難以處理,不過這隻是針對於虛擬機器的實現來說,因為這一部分記憶體是要實現自動記憶體管理系統(GC)的。

     全域共用的這部分記憶體(以下簡稱堆),記憶體配置主要是由程式員顯示的使用new關鍵字來觸發的,至於new出來的這部分記憶體在哪分配,如何分配,則是JAVA虛擬機器來決定。而這部分記憶體的釋放,則是由自動記憶體管理系統(以下簡稱GC)來管理的

     通常情況下,堆記憶體配置是要依賴於GC的策略與實現的,在分配的時候,就要考慮好到時候如何回收這部分記憶體。也是正因為如此,對於記憶體配置這一部分的講解來說,我們必須得先瞭解記憶體是如何被回收的,才能更好的理解記憶體要怎麼被分配。

結束語

      本次對於JAVA語言中記憶體管理的概述就到此結束了,接下來的章節會著重講解一下GC的原理以及實現方式,請各位敬請期待吧。

 

JVM記憶體管理------JAVA語言的記憶體管理概述

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.