最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java程序運(yùn)行時(shí)內(nèi)存分配詳解

 更新時(shí)間:2016年07月20日 21:46:52   投稿:mdxy-dxy  
這篇文章主要介紹了java程序運(yùn)行時(shí)內(nèi)存分配詳解 ,需要的朋友可以參考下

一、 基本概念

   每運(yùn)行一個(gè)java程序會(huì)產(chǎn)生一個(gè)java進(jìn)程,每個(gè)java進(jìn)程可能包含一個(gè)或者多個(gè)線程,每一個(gè)Java進(jìn)程對(duì)應(yīng)唯一一個(gè)JVM實(shí)例,每一個(gè)JVM實(shí)例唯一對(duì)應(yīng)一個(gè)堆,每一個(gè)線程有一個(gè)自己私有的棧。進(jìn)程所創(chuàng)建的所有類的實(shí)例(也就是對(duì)象)或數(shù)組(指的是數(shù)組的本身,不是引用)都放在堆中,并由該進(jìn)程所有的線程共享。Java中分配堆內(nèi)存是自動(dòng)初始化的,即為一個(gè)對(duì)象分配內(nèi)存的時(shí)候,會(huì)初始化這個(gè)對(duì)象中變量。雖然Java中所有對(duì)象的存儲(chǔ)空間都是在堆中分配的,但是這個(gè)對(duì)象的引用卻是在棧中分配,也就是說在建立一個(gè)對(duì)象時(shí)在堆和棧中都分配內(nèi)存,在堆中分配的內(nèi)存實(shí)際存放這個(gè)被創(chuàng)建的對(duì)象的本身,而在棧中分配的內(nèi)存只是存放指向這個(gè)堆對(duì)象的引用而已。局部變量 new 出來時(shí),在??臻g和堆空間中分配空間,當(dāng)局部變量生命周期結(jié)束后,棧空間立刻被回收,堆空間區(qū)域等待GC回收。

具體的概念:JVM的內(nèi)存可分為3個(gè)區(qū):堆(heap)、棧(stack)和方法區(qū)(method,也叫靜態(tài)區(qū)):

堆區(qū):

1.存儲(chǔ)的全部是對(duì)象,每個(gè)對(duì)象都包含一個(gè)與之對(duì)應(yīng)的class的信息(class的目的是得到操作指令) ;
2.jvm只有一個(gè)堆區(qū)(heap),且被所有線程共享,堆中不存放基本類型和對(duì)象引用,只存放對(duì)象本身和數(shù)組本身;

棧區(qū):
1.每個(gè)線程包含一個(gè)棧區(qū),棧中只保存基礎(chǔ)數(shù)據(jù)類型本身和自定義對(duì)象的引用;
2.每個(gè)棧中的數(shù)據(jù)(原始類型和對(duì)象引用)都是私有的,其他棧不能訪問;
3.棧分為3個(gè)部分:基本類型變量區(qū)、執(zhí)行環(huán)境上下文、操作指令區(qū)(存放操作指令);

方法區(qū)(靜態(tài)區(qū)):
1.被所有的線程共享,方法區(qū)包含所有的class(class是指類的原始代碼,要?jiǎng)?chuàng)建一個(gè)類的對(duì)象,首先要把該類的代碼加載到方法區(qū)中,并且初始化)和static變量。
2.方法區(qū)中包含的都是在整個(gè)程序中永遠(yuǎn)唯一的元素,如class,static變量。
 

二、實(shí)例演示

AppMain.java

public class AppMain   //運(yùn)行時(shí), jvm 把a(bǔ)ppmain的代碼全部都放入方法區(qū)  
{  
public static void main(String[] args) //main 方法本身放入方法區(qū)。  
{  
Sample test1 = new Sample( " 測(cè)試1 " ); //test1是引用,所以放到棧區(qū)里, Sample是自定義對(duì)象應(yīng)該放到堆里面  
Sample test2 = new Sample( " 測(cè)試2 " );  
 
test1.printName();  
test2.printName();  
}  
}  
 
public class Sample  //運(yùn)行時(shí), jvm 把a(bǔ)ppmain的信息都放入方法區(qū)  
{  
/** 范例名稱 */  
private String name; //new Sample實(shí)例后, name 引用放入棧區(qū)里, name 對(duì)應(yīng)的 String 對(duì)象放入堆里  
 
/** 構(gòu)造方法 */  
public Sample(String name)  
{  
this .name = name;  
}  
 
/** 輸出 */  
public void printName() //在沒有對(duì)象的時(shí)候,print方法跟隨sample類被放入方法區(qū)里。  
{  
System.out.println(name);  
}  
}

運(yùn)行該程序時(shí),首先啟動(dòng)一個(gè)Java虛擬機(jī)進(jìn)程,這個(gè)進(jìn)程首先從classpath中找到AppMain.class文件,讀取這個(gè)文件中的二進(jìn)制數(shù)據(jù),然后把Appmain類的類信息存放到運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)中,這就是AppMain類的加載過程。

接著,Java虛擬機(jī)定位到方法區(qū)中AppMain類的Main()方法的字節(jié)碼,開始執(zhí)行它的指令。這個(gè)main()方法的第一條語句就是:

復(fù)制代碼 代碼如下:

  Sample test1=new Sample("測(cè)試1");
 

該語句的執(zhí)行過程:
    1、 Java虛擬機(jī)到方法區(qū)找到Sample類的類型信息,沒有找到,因?yàn)镾ample類還沒有加載到方法區(qū)(這里可以看出,java中的內(nèi)部類是單獨(dú)存在的,而且剛開始的時(shí)候不會(huì)跟隨包含類一起被加載,等到要用的時(shí)候才被加載)。Java虛擬機(jī)立馬加載Sample類,把Sample類的類型信息存放在方法區(qū)里。
    2、 Java虛擬機(jī)首先在堆區(qū)中為一個(gè)新的Sample實(shí)例分配內(nèi)存, 并在Sample實(shí)例的內(nèi)存中存放一個(gè)方法區(qū)中存放Sample類的類型信息的內(nèi)存地址。
    3、 JVM的進(jìn)程中,每個(gè)線程都會(huì)擁有一個(gè)方法調(diào)用棧,用來跟蹤線程運(yùn)行中一系列的方法調(diào)用過程,棧中的每一個(gè)元素就被稱為棧幀,每當(dāng)線程調(diào)用一個(gè)方法的時(shí)候就會(huì)向方法棧壓入一個(gè)新幀。這里的幀用來存儲(chǔ)方法的參數(shù)、局部變量和運(yùn)算過程中的臨時(shí)數(shù)據(jù)。

    4、位于“=”前的Test1是一個(gè)在main()方法中定義的一個(gè)變量(一個(gè)Sample對(duì)象的引用),因此,它被會(huì)添加到了執(zhí)行main()方法的主線程的JAVA方法調(diào)用棧中。而“=”將把這個(gè)test1變量指向堆區(qū)中的Sample實(shí)例。
    5、JVM在堆區(qū)里繼續(xù)創(chuàng)建另一個(gè)Sample實(shí)例,并在main方法的方法調(diào)用棧中添加一個(gè)Test2變量,該變量指向堆區(qū)中剛才創(chuàng)建的Sample新實(shí)例。

    6、JVM依次執(zhí)行它們的printName()方法。當(dāng)JAVA虛擬機(jī)執(zhí)行test1.printName()方法時(shí),JAVA虛擬機(jī)根據(jù)局部變量test1持有的引用,定位到堆區(qū)中的Sample實(shí)例,再根據(jù)Sample實(shí)例持有的引用,定位到方法去中Sample類的類型信息,從而獲得printName()方法的字節(jié)碼,接著執(zhí)行printName()方法包含的指令,開始執(zhí)行。

三、辨析

  在Java語言里堆(heap)和棧(stack)里的區(qū)別 :
    1. 棧(stack)與堆(heap)都是Java用來在Ram中存放數(shù)據(jù)的地方。與C++不同,Java自動(dòng)管理?xiàng):投?,程序員不能直接地設(shè)置?;蚨?。
  2. 棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。另外,棧數(shù)據(jù)可以共享(詳見下面的介紹)。堆的優(yōu)勢(shì)是可以動(dòng)態(tài)地分配內(nèi)存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會(huì)自動(dòng)收走這些不再使用的數(shù)據(jù)。但缺點(diǎn)是,由于要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢。

Java中的2種數(shù)據(jù)類型:

  一種是基本類型(primitive types), 共有8類,即int, short, long, byte, float, double, boolean, char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動(dòng)變量。自動(dòng)變量存的是字面值,不是類的實(shí)例,即不是類的引用,這里并沒有類的存在。如int a = 3; 這里的a是一個(gè)指向int類型的引用,指向3這個(gè)字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值固定定義在某個(gè)程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。
  

    棧有一個(gè)很重要的特性:存在棧中的數(shù)據(jù)可以共享。假設(shè)我們同時(shí)定義:  int a = 3;  int b = 3;  編譯器先處理int a = 3;首先它會(huì)在棧中創(chuàng)建一個(gè)變量為a的引用,然后查找有沒有字面值為3的地址,如果沒找到,就開辟一個(gè)存放3這個(gè)字面值的地址,然后將a指向3的地址。接著處理int b = 3;在創(chuàng)建完b的引用變量后,由于在棧中已經(jīng)有3這個(gè)字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。

  這種字面值的引用與類對(duì)象的引用不同。假定兩個(gè)類對(duì)象的引用同時(shí)指向一個(gè)對(duì)象,如果一個(gè)對(duì)象引用變量修改了這個(gè)對(duì)象的內(nèi)部狀態(tài),那么另一個(gè)對(duì)象引用變量也即刻反映出這個(gè)變化。相反,通過字面值的引用來修改其值,不會(huì)導(dǎo)致另一個(gè)指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與 b的值后,再令a=4;那么,b不會(huì)等于4,還是等于3。在編譯器內(nèi)部,遇到a=4;時(shí),它就會(huì)重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個(gè)地址。因此a值的改變不會(huì)影響到b的值。
  另一種是包裝類數(shù)據(jù),如Integer, String, Double等將相應(yīng)的基本數(shù)據(jù)類型包裝起來的類。這些類數(shù)據(jù)全部存在于堆中,Java用new()語句來顯示地告訴編譯器,在運(yùn)行時(shí)才根據(jù)需要?jiǎng)討B(tài)創(chuàng)建,因此比較靈活,但缺點(diǎn)是要占用更多的時(shí)間。

四、總結(jié)

      java內(nèi)存分配條理還是很清楚的,如果要徹底搞懂,可以去查閱JVM相關(guān)的書籍。在java中,內(nèi)存分配最讓人頭疼的是String對(duì)象,由于其特殊性,所以很多程序員容易搞混淆,下一篇文章再詳細(xì)講解。

相關(guān)文章

  • Java的Hibernate框架中的基本映射用法講解

    Java的Hibernate框架中的基本映射用法講解

    映射是Hibernate框架操作數(shù)據(jù)庫(kù)數(shù)據(jù)的重要特性之一,這里我們來看一下Java的Hibernate框架中的基本映射用法講解,包括最基本的單向一對(duì)一與多對(duì)一映射關(guān)系等:
    2016-07-07
  • SpringBoot如何在線程中獲取@Service Bean類

    SpringBoot如何在線程中獲取@Service Bean類

    這篇文章主要介紹了SpringBoot如何在線程中獲取@Service Bean類,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 并發(fā)編程模式之ThreadLocal源碼和圖文解讀

    并發(fā)編程模式之ThreadLocal源碼和圖文解讀

    這篇文章主要介紹了并發(fā)編程模式之ThreadLocal源碼和圖文解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java實(shí)現(xiàn)京東聯(lián)盟API數(shù)據(jù)獲取功能

    Java實(shí)現(xiàn)京東聯(lián)盟API數(shù)據(jù)獲取功能

    這篇文章介紹了Java獲取京東聯(lián)盟API數(shù)據(jù)的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • JAVA定義變量與輸出詳解

    JAVA定義變量與輸出詳解

    這篇文章主要介紹了JAVA定義變量與輸出詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Struts2修改上傳文件大小限制方法解析

    Struts2修改上傳文件大小限制方法解析

    這篇文章主要介紹了Struts2修改上傳文件大小限制的相關(guān)內(nèi)容,包括決定Struts2上傳文件大小的因素,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-09-09
  • java-spark中各種常用算子的寫法示例

    java-spark中各種常用算子的寫法示例

    這篇文章主要給大家介紹了關(guān)于java-spark中各種常用算子的寫法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • 一文詳解如何排查定位Java中的死鎖

    一文詳解如何排查定位Java中的死鎖

    在當(dāng)今數(shù)字化時(shí)代,微服務(wù)架構(gòu)憑借其高可擴(kuò)展性、靈活性和易于維護(hù)等優(yōu)勢(shì),成為了眾多企業(yè)構(gòu)建大型應(yīng)用系統(tǒng)的首選架構(gòu)模式,當(dāng)我們將微服務(wù)部署在 Linux 服務(wù)器上時(shí),有時(shí)會(huì)遭遇令人頭疼的死鎖問題,本位給大家介紹了如何排查定位Java中的死鎖,需要的朋友可以參考下
    2025-02-02
  • JVM致命錯(cuò)誤日志詳解(最新推薦)

    JVM致命錯(cuò)誤日志詳解(最新推薦)

    這篇文章主要介紹了JVM致命錯(cuò)誤日志詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Spring Boot 項(xiàng)目發(fā)布到 Tomcat 服務(wù)器的操作步驟

    Spring Boot 項(xiàng)目發(fā)布到 Tomcat 服務(wù)器的操作步驟

    這篇文章主要介紹了Spring Boot 項(xiàng)目發(fā)布到 Tomcat 服務(wù)器的操作步驟,需要的朋友可以參考下
    2017-04-04

最新評(píng)論

澄迈县| 玛沁县| 隆昌县| 色达县| 左权县| 石景山区| 兰溪市| 贵阳市| 吴旗县| 民乐县| 平罗县| 古田县| 晋城| 镇原县| 大足县| 马尔康县| 黎川县| 玉山县| 安塞县| 淮北市| 林甸县| 雷波县| 怀宁县| 师宗县| 耒阳市| 铁岭县| 青川县| 普洱| 会泽县| 丰城市| 黔西| 无极县| 利川市| 贵德县| 徐州市| 阆中市| 沿河| 哈尔滨市| 黄石市| 苍山县| 堆龙德庆县|