Java運(yùn)行時(shí)數(shù)據(jù)區(qū)域(內(nèi)存劃分)的深入講解
1. 程序計(jì)數(shù)器(線程私有)
程序計(jì)數(shù)器是一塊比較小的內(nèi)存空間,可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器(切換線程后,能恢復(fù)到正確的執(zhí)行位置).
2. Java虛擬機(jī)棧(線程私有)
(1) 概念
虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型 : 每個(gè)方法執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口 等信息。每一個(gè)方法從調(diào)用直至執(zhí)行完成的過程,就對(duì)應(yīng)一個(gè)棧幀在虛擬機(jī)棧中入棧和出棧的過程。聲明周期與線程相同。
關(guān)于棧幀的理解: 創(chuàng)建啟動(dòng)一個(gè)線程,就創(chuàng)建了一個(gè)虛擬機(jī)棧空間(存放多個(gè)節(jié)點(diǎn),先進(jìn)后出).可能出現(xiàn)兩種異常: ①StackOverflowError: 方法調(diào)用鏈太深(如遞歸); ②OOM
(2) 下面我們來分析一段代碼
public class VMStackTest { public static void main(String[] args) { int m = 1; int n = 2; swap1(1, 2); System.out.printf("main:m=%s, n=%s%n", m, n); } private static void swap1(int m, int n) { int tmp = m; m = n; n = tmp; Person p1 = new Person("p1"); Person p2 = new Person("p2"); swap2(p1, p2); System.out.printf("swap1:p1=%s, p2=%s%n", p1.name, p2.name); } private static void swap2(Person p1, Person p2) { Person tmp = p1; p1 = p2; p2 = tmp; System.out.printf("swap2:p1=%s, p2=%s%n", p1.name, p2.name); } static class Person{ String name; public Person(String name) { this.name = name; } } }
這段代碼的執(zhí)行結(jié)果是什么?
我們知道,Java中只有值傳遞,當(dāng)為基本數(shù)據(jù)類型時(shí),傳的是字面值常量,當(dāng)為引用類型,傳的是地址.
swap1中,只是修改了方法棧幀中的局部變量,對(duì)外面的局部變量不起作用,所以swap1中的交換是無效的.
swap2中也一樣,只是修改了方法棧幀中的局部變量,對(duì)外面的局部變量交換也是無效的.
所以最終的打印結(jié)果為:
如果要把p1,p2對(duì)象的名稱調(diào)換,p1.name="p2", p2.name="p1"(作用在堆里邊的對(duì)象)
3. 本地方法棧(線程私有)
本地方法棧與虛擬機(jī)棧的作用完全一樣,他倆的區(qū)別無非是本地方法棧為虛擬機(jī)使用的Native方法服務(wù),而虛擬機(jī)棧為JVM執(zhí)行的Java方法服務(wù)。
4. Java堆(線程共享)
Java堆(Java Heap)是JVM所管理的最大內(nèi)存區(qū)域。Java堆是所有線程共享的一塊區(qū)域,在JVM啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域存放的都是對(duì)象實(shí)例。JVM規(guī)范中說到:"所有的對(duì)象實(shí)例以及數(shù)組都要在堆上分配"。
5. 方法區(qū)(線程共享)
方法區(qū)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域。它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量(jdk1.7在方法區(qū)中;1.8在堆中)、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
6. 運(yùn)行時(shí)常量池(方法區(qū)的一部分)
(1) 概念
運(yùn)行時(shí)常量池是方法區(qū)的一部分,存放字面量與符號(hào)引用。
字面量 : 字符串(JDK1.7后移動(dòng)到堆中) 、final常量、基本數(shù)據(jù)類型的值。
符號(hào)引用 : 類和結(jié)構(gòu)的完全限定名、字段的名稱和描述符、方法的名稱和描述符。
(2) 補(bǔ)充: 其他常量池
① class文件常量池: Java文件編譯為class字節(jié)碼文件,存在的常量池,包含字面量和符號(hào)引用.
② Java進(jìn)程運(yùn)行后,即使沒有執(zhí)行到某行代碼,也已經(jīng)把class文件常量池中的內(nèi)容放在運(yùn)行時(shí)常量池,如下圖:
③ 字符串常量池: 1.7之前是在運(yùn)行時(shí)常量池里面,1.7之后,是在堆里面.
總結(jié)
到此這篇關(guān)于Java運(yùn)行時(shí)數(shù)據(jù)區(qū)域(內(nèi)存劃分)的文章就介紹到這了,更多相關(guān)Java運(yùn)行時(shí)內(nèi)存劃分內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java中對(duì)字符串每個(gè)字符統(tǒng)計(jì)的方法
java中對(duì)字符串每個(gè)字符統(tǒng)計(jì)的方法,需要的朋友可以參考一下2013-03-03springboot整合RabbitMQ中死信隊(duì)列的實(shí)現(xiàn)
死信是無法被消費(fèi)的消息,產(chǎn)生原因包括消息TTL過期、隊(duì)列最大長度達(dá)到以及消息被拒絕且不重新排隊(duì),RabbitMQ的死信隊(duì)列機(jī)制能夠有效防止消息數(shù)據(jù)丟失,適用于訂單業(yè)務(wù)等場景,本文就來介紹一下2024-10-10基于javascript實(shí)現(xiàn)獲取最短路徑算法代碼實(shí)例
這篇文章主要介紹了基于javascript實(shí)現(xiàn)獲取最短路徑算法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02JAVA設(shè)計(jì)模式之訪問者模式原理與用法詳解
這篇文章主要介紹了JAVA設(shè)計(jì)模式之訪問者模式,簡單說明了訪問者模式的原理,并結(jié)合實(shí)例分析了java訪問者模式的定義與用法,需要的朋友可以參考下2017-08-08Java 數(shù)據(jù)結(jié)構(gòu)之時(shí)間復(fù)雜度與空間復(fù)雜度詳解
算法復(fù)雜度分為時(shí)間復(fù)雜度和空間復(fù)雜度。其作用: 時(shí)間復(fù)雜度是度量算法執(zhí)行的時(shí)間長短;而空間復(fù)雜度是度量算法所需存儲(chǔ)空間的大小2021-11-11Java基于HttpClient實(shí)現(xiàn)RPC的示例
HttpClient可以實(shí)現(xiàn)使用Java代碼完成標(biāo)準(zhǔn)HTTP請(qǐng)求及響應(yīng)。本文主要介紹了Java基于HttpClient實(shí)現(xiàn)RPC,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10