Java程式在記憶體中運行詳解

来源:https://www.cnblogs.com/tester-ggf/archive/2019/11/24/11921034.html
-Advertisement-
Play Games

[TOC] Java程式在記憶體中運行詳解 Java語言是一門編譯型語言,需要將編寫的源代碼(.java文件)編譯之後(.class位元組碼文件),通過 jvm 才能正常的執行,下麵的內容記錄了一個程式從編寫到執行整個過程在記憶體中是怎麼一個變的。 一、JVM的記憶體分佈 先瞭解下 JVM 的記憶體分佈,因為 ...


目錄

Java程式在記憶體中運行詳解

Java語言是一門編譯型語言,需要將編寫的源代碼(.java文件)編譯之後(.class位元組碼文件),通過 jvm 才能正常的執行,下麵的內容記錄了一個程式從編寫到執行整個過程在記憶體中是怎麼一個變的。

一、JVM的記憶體分佈

先瞭解下 JVM 的記憶體分佈,因為Java程式想要運行,就要依靠 JVM,可以把JVM理解成Java程式和操作系統之間的橋梁,JVM 實現了Java 的平臺無關性,由此可見JVM的重要性。所以在學習 Java 記憶體分配原理的時候一定要牢記這一切都是在 JVM 中進行的,JVM 是記憶體分配原理的基礎與前提。

1.jvm記憶體分佈圖

從圖片中看,一共分為了5大區域,分別是:方法區、堆、棧、本地方法區、程式計數器。

這裡我們主要瞭解下 方法區堆、 棧、這三個區域。

2.方法區:

方法區是一塊所有線程共用的記憶體區域。
保存系統的類信息,比如,類的欄位,方法,常量池等等。

方法區的大小決定了系統可以保存多少個類,如果系統定義了太多的類,導致方法區溢出,虛擬機同樣會拋出記憶體溢出的錯誤

jdk1.6和jdk1.7方法區可以理解為永久區。

jdk1.8已經將方法區取消,替代的是元數據區。

jdk1.8的元數據區可以使用參數-XX:MaxMetaspaceSzie設定大小,這是一塊堆外的直接記憶體,與永久區不同,如果不指定大小,預設情況下,虛擬機會耗盡可用系統記憶體。

3.堆:

用來存放動態產生的數據,比如new出來的對象。註意創建出來的對象只包含屬於各自的成員變數,並不包括成員方法。因為同一個類的對象擁有各自的成員變數,存儲在各自的堆中,但是他們共用該類的方法,並不是每創建一個對象就把成員方法複製一次。在堆中只會存儲成員方法的地址,在調用的時候,根據地址去方法區中執行對應的成員方法。

4. 棧:

棧生命周期與線程相同。啟動一個線程,程式調用函數,棧幀被壓入棧中,函數調用結束,相應的是棧幀的出棧。

棧幀由局部變數表,操作數棧,幀數據區組成。

局部變數表:存放的是函數的入參,以及局部變數。

操作數棧:存放調用過程中的計算結果的臨時存放區域。

幀數據區:存放的是異常處理表和函數的返回,訪問常量池的指針。

舉個例子,線程執行進入方法A,則會創建棧幀入棧,A方法調用了B方法,B棧幀入棧,B方法中調用C方法,C創建了棧幀壓入棧中,接下來是D入棧

反過來,D方法執行完,棧幀出棧,接著是C、B、A。

jvm記憶體模型詳解記錄

二、程式執行的過程

從上圖我們看到了一個程式在記憶體中執行的過程。

上圖的執行流程:

1.從 disk 中將 MainApp.class 載入到 jvm 的方法區中。

2.執行 main 方法,將該 main 方法中包含的變數和函數,壓到棧中。

3.開始執行 main 方法中的指令,創建一個 animal 對象, 將 new 出來的 animal 對象存儲到堆中,animal 引用指向堆中的 animal 對象,堆中的 animal 對象指向方法區中的 Animal 類。

4.繼續執行 main 方法中的指令,調用 animal 對象中的 printName() 方法,這時 animal 應用調用 animal 對象, animal 對象找到方法區的 Animal 類中的 printName() 位元組碼信息,根據該描述信息,開始執行 printName方法。

三、只有一個對象時的記憶體圖

從左側我們看到有兩個類,按照Java程式的執行流程,會把這兩個類編譯成 .class 文件,即圖中最右邊的 Phone.class he Demo01PhoneOne.class。

首先程式開始執行是從 main() 方法開始,這個時候會把 main() 方法壓到棧中,main() 方法中的第一句代碼是先創建一個 Phone 對象,當我們 new 一個對象時,會把 new 出來的對象放到堆中,相對應的給這個對象分配一個地址值,在棧中會產生一個實例 one 會指向這個地址,可以看到堆中的對象包含了自身的成員變數和成員方法的引用。

接著繼續執行下麵的代碼,直接列印對象的屬性值,由於對象屬性沒有進行賦值,所以輸出的都是對應數據類型的預設值。 繼續下麵的操作,就是給對象的屬性進行賦值,由於 one 是指向了對象,所以直接可以進行操作,這時在堆中的屬性值就會被賦予對應的值了。再次列印的時候就會列印出對應的值。

再到後面,繼續調用了對象的成員方法,這個時候需要先在堆中找到這個成員方法的應用,然後找到方法區中將對應的代碼壓到棧中,繼續執行。調用方法會傳入對應的參數,也是放到棧中的,執行完這個方法之後,壓到棧中的這一部分代碼就會出棧,直到 main() 方法中所有的代碼執行完,棧中的內容也就全部消失,記憶體也就隨之釋放。

四、兩個對象使用同一個方法的記憶體圖

這裡和上面不同的是創建了兩個對象,但是操作的內容還是和上面一樣的。唯一區別就是在調用成員方法時,調用的是同一個。

剛開始也說到了,同一個類創建多個對象時,他們是各自擁有自己的成員變數了,但是應用的成員方法卻是同一個。

從圖中我們就可以看出,給兩個對象進行賦值時,是會列印出不同的值的。調用方法時,使用的還是同一個方法。

五、兩個引用指向同一個對象的記憶體圖

當我理解了前面兩個圖後,看到這裡應該也不會有什麼難度了,這裡我們只 new 了一個對象,但是卻有兩個實例,從圖中也可以看到堆裡面只有一個對象。

看到圖最左邊,我們把 one 實例直接就賦值給了 two, 其實就是把 one 的地址值賦給了 two, 這時 two 也就和one 指向了同一個對象。這時去改變對象中的值,就會把 one 原來賦的值直接覆蓋掉。最終列印的就是 two 實例賦的值了。

六、使用對象類型作為方法參數的記憶體圖

使用對象類型作為方法的參數,在傳遞的過程中,實際上傳遞的是引用,即對象的地址值。當我們在另外一個方法中改變了這個對象的屬性時,對象原來的值就會被覆蓋。

七、對象類型作為方法返回值得記憶體圖

對象類型作為返回值也是一樣的道理,返回的實際是對象的地址值。

八、總結

  1. 分清什麼是實例什麼是對象。Class a= new Class(); 此時 a 叫實例,而不能說 a 是對象。實例在棧中,對象在堆中,操作實例實際上是通過實例的指針間接操作對象。多個實例可以指向同一個對象。

  2. 棧中的數據和堆中的數據銷毀並不是同步的。方法一旦結束,棧中的局部變數立即銷毀,但是堆中對象不一定銷毀。因為可能有其他變數也指向了這個對象,直到棧中沒有變數指向堆中的對象時,它才銷毀,而且還不是馬上銷毀,要等垃圾回收掃描時才可以被銷毀。

  3. 以上的棧、堆、代碼段、數據段等等都是相對於應用程式而言的。每一個應用程式都對應唯一的一個JVM實例,每一個JVM實例都有自己的記憶體區域,互不影響。並且這些記憶體區域是所有線程共用的。這裡提到的棧和堆都是整體上的概念,這些堆棧還可以細分。

  4. 類的成員變數在不同對象中各不相同,都有自己的存儲空間(成員變數在堆中的對象中)。而類的方法卻是該類的所有對象共用的,只有一套,對象使用方法的時候方法才被壓入棧,方法不使用則不占用記憶體。

  5. 對象類型作為方法的參數或者方法的返回值時,傳遞的都是對象的地址值。再其他地方修改這個對象的屬性值時,原有的值就會被覆蓋掉。

參考文章:

https://blog.csdn.net/yangyuankp/article/details/7651251

http://www.yq1012.com/jichu/4540.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Git的三種狀態和三個區域是什麼?瞭解Git團隊代碼合作的流程嗎?知道rebase和merge的區別嗎? ...
  • 可控自定義組件: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="js/react.js"></script> <script src="js/react-dom.js"></scri ...
  • UML類圖幾種關係的總結,泛化 = 實現 > 組合 > 聚合 > 關聯 > 依賴在UML類圖中,常見的有以下幾種關係: 泛化(Generalization), 實現(Realization),關聯(Association),聚合(Aggregation),組合(Composition),依賴(Dep ...
  • https://dvteclipse.com/documentation/svlinter/How_to_use_special_characters_in_XML.3F.html Because XML syntax uses some characters for tags and attrib ...
  • 生成條形碼 <body> <div> <img id="ma"/> </div> </body> </html> <script src="jquery-1.8.1.min.js"></script> <script type="text/javascript" src="https://cdn.b ...
  • 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現。 下麵就是我的學習筆記,對於Javascript初學者應該是很有用的。 一、變數的作用域 要理解閉包,首先必須理解Javascript特殊的變數作用域。 變數的作用域無非就是兩種:全局變數和局部變 ...
  • 12-Factor與雲原生雲原生應用今天先到這兒,希望對技術領導力, 企業管理,系統架構設計與評估,團隊管理, 項目管理, 產品管理,團隊建設 有參考作用 , 您可能感興趣的文章: 精益IT組織與分享式領導領導人怎樣帶領好團隊構建創業公司突擊小團隊國際化環境下系統架構演化微服務架構設計視頻直播平臺的... ...
  • 1 介紹 MongoDB中文社區(mongoing.com)是大中華區獲得官方認可的中文社區,11月23日下午,在廣州舉辦了線下用戶大會,帶給大家一手乾貨和實踐。 2 大會議程 大會組織者對時間的把控做得非常好,沒有拖沓,基本是按時既定流程走的。具體流程如下: 3 一些個人收穫 3.1 MongoD ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...