中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
Java內(nèi)存分配、管理小結(jié)

首先是概念層面的幾個問題:

 

  • Java中運(yùn)行時內(nèi)存結(jié)構(gòu)有哪幾種?
  • Java中為什么要設(shè)計堆棧分離?
  • Java多線程中是如何實(shí)現(xiàn)數(shù)據(jù)共享的?
  • Java反射的基礎(chǔ)是什么?

然后是運(yùn)用層面:

  • 引用類型變量和對象的區(qū)別?
  • 什么情況下用局部變量,什么情況下用成員變量?
  • 數(shù)組如何初始化?聲明一個數(shù)組的過程中,如何分配內(nèi)存?
  • 聲明基本類型數(shù)組和聲明引用類型的數(shù)組,初始化時,內(nèi)存分配機(jī)制有什么區(qū)?
  • 在什么情況下,我們的方法設(shè)計為靜態(tài)化,為什么?(上次胡老師問文奇,問的啞口無言,當(dāng)時想回答,卻老感覺表述不清楚,這里也簡單說明一下)

好了,問題提完了,如果您都能一眼看出答案,那么,沒有必要再浪費(fèi)您寶貴的時間看下去了。

如果您還不太明白,請跟隨我一路走下去。

 

Java中運(yùn)行時內(nèi)存結(jié)構(gòu)

   1.1 方法區(qū): 

方法區(qū)是系統(tǒng)分配的一個內(nèi)存邏輯區(qū)域,是JVM在裝載類文件時,用于存儲類型信息的(類的描述信息)。

    

方法區(qū)存放的信息包括:

            1.1.1類的基本信息:

  1. 每個類的全限定名
  2. 每個類的直接超類的全限定名(可約束類型轉(zhuǎn)換)
  3. 該類是類還是接口
  4. 該類型的訪問修飾符
  5. 直接超接口的全限定名的有序列表

             1.1.2已裝載類的詳細(xì)信息

  1.  運(yùn)行時常量池

    在方法區(qū)中,每個類型都對應(yīng)一個常量池,存放該類型所用到的所有常量,常量池中存儲了諸如文字字符串、final變量值、類名和方法名常量。它們以數(shù)組形式通過索引被訪問,是外部調(diào)用與類聯(lián)系及類型對象化的橋梁。(存的可能是個普通的字符串,然后經(jīng)過常量池解析,則變成指向某個類的引用)

  2.  字段信息

    字段信息存放類中聲明的每一個字段的信息,包括字段的名、類型、修飾符。

    字段名稱指的是類或接口的實(shí)例變量或類變量,字段的描述符是一個指示字段的類型的字符串,如private A a=null;a為字段名,A為描述符,private為修飾符

  3.  方法信息

    類中聲明的每一個方法的信息,包括方法名、返回值類型、參數(shù)類型、修飾符、異常、方法的字節(jié)碼。

    (在編譯的時候,就已經(jīng)將方法的局部變量、操作數(shù)棧大小等確定并存放在字節(jié)碼中,在裝載的時候,隨著類一起裝入方法區(qū)。)

    在運(yùn)行時,JVM從常量池中獲得符號引用,然后在運(yùn)行時解析成引用項的實(shí)際地址,最后通過常量池中的全限定名、方法和字段描述符,把當(dāng)前類或接口中的代碼與其它類或接口中的代碼聯(lián)系起來。
  4.  靜態(tài)變量

    這個沒什么好說的,就是類變量,類的所有實(shí)例都共享,我們只需知道,在方法區(qū)有個靜態(tài)區(qū),靜態(tài)區(qū)專門存放靜態(tài)變量和靜態(tài)塊。

  5.  到類classloader的引用到該類的類裝載器的引用。
  6.  到類class 的引用虛擬機(jī)為每一個被裝載的類型創(chuàng)建一個class 實(shí)例,用來代表這個被裝載的類。 

    由此我們可以知道反射的基礎(chǔ)

在裝載類的時候,加入方法區(qū)中的所有信息,最后都會形成Class類的實(shí)例,代表這個被裝載的類。方法區(qū)中的所有的信息,都是可以通過這個Class類對象反射得到。我們知道對象是類的實(shí)例,類是相同結(jié)構(gòu)的對象的一種抽象。同類的各個對象之間,其實(shí)是擁有相同的結(jié)構(gòu)(屬性),擁有相同的功能(方法),各個對象的區(qū)別只在于屬性值的不同
    同樣的,我們所有的類,其實(shí)都是Class類的實(shí)例,他們都擁有相同的結(jié)構(gòu)-----Field數(shù)組、Method數(shù)組。而各個類中的屬性都是Field屬性的一個具體屬性值,方法都是Method屬性的一個具體屬性值。


 

 在運(yùn)行時,JVM從常量池中獲得符號引用,然后在運(yùn)行時解析成引用項的實(shí)際地址,最后通過常量池中的全限定名、方法和字段描述符,把當(dāng)前類或接口中的代碼與其它類或接口中的代碼聯(lián)系起來。

 

1.2 Java棧

JVM棧是程序運(yùn)行時單位,決定了程序如何執(zhí)行,或者說數(shù)據(jù)如何處理。

Java中,一個線程就會有一個線程的JVM棧與之對應(yīng),因?yàn)椴贿^的線程執(zhí)行邏輯顯然不同,因此都需要一個獨(dú)立的JVM棧來存放該線程的執(zhí)行邏輯。

對方法的調(diào)用:

Java棧內(nèi)存,以的形式存放本地方法調(diào)用狀態(tài),包括方法調(diào)用的參數(shù)局部變量、中間結(jié)果等(方法都是以方法幀的形式存放在方法區(qū)的),每調(diào)用一個方法就將對應(yīng)該方法的方法幀壓入Java 棧,成為當(dāng)前方法幀。當(dāng)調(diào)用結(jié)束(返回)時,就彈出該幀。

 

這意味著:

在方法中定義的一些基本類型的變量和引用變量都在方法的棧內(nèi)存中分配。當(dāng)在一段代碼塊定義一個變量時,Java 就在棧中為這個變量分配內(nèi)存空間,當(dāng)超過變量的作用域后(方法執(zhí)行完成后),Java 會自動釋放掉為該變量所分配的內(nèi)存空間,該內(nèi)存空間可以立即被另作它用。--------同時,因?yàn)樽兞勘会尫?,該變量對?yīng)的對象,也就失去了引用,也就變成了可以被gc對象回收的垃圾。


因此我們可以知道成員變量與局部變量的區(qū)別:

局部變量,在方法內(nèi)部聲明,當(dāng)該方法運(yùn)行完時,內(nèi)存即被釋放。
成員變量,只要該對象還在,哪怕某一個方法運(yùn)行完了,還是存在。
從系統(tǒng)的角度來說,聲明局部變量有利于內(nèi)存空間的更高效利用(方法運(yùn)行完即回收)。
成員變量可用于各個方法間進(jìn)行數(shù)據(jù)共享。

 

 

Java 棧內(nèi)存的組成:
局部變量區(qū)、操作數(shù)棧、幀數(shù)據(jù)區(qū)組成。
(1):局部變量區(qū)為一個以字為單位的數(shù)組,每個數(shù)組元素對應(yīng)一個局部變量的值。調(diào)用方法時,將方法的局部變量組成一個數(shù)組,通過索引來訪問。若為非靜態(tài)方法,則加入一個隱含的引用參數(shù)this,該參數(shù)指向調(diào)用這個方法的對象。而靜態(tài)方法則沒有this參數(shù)。因此,對象無法調(diào)用靜態(tài)方法。

 

由此,我們可以知道,方法什么時候設(shè)計為靜態(tài),什么時候?yàn)榉庆o態(tài)?

前面已經(jīng)說過,對象是類的一個實(shí)例,各個對象結(jié)構(gòu)相同,只是屬性不同。
而靜態(tài)方法是對象無法調(diào)用的。
所以,靜態(tài)方法適合那些工具類中的工具方法,這些類只是用來實(shí)現(xiàn)一些功能,也不需要產(chǎn)生對象,通過設(shè)置對象的屬性來得到各個不同的個體。


(2):操作數(shù)棧也是一個數(shù)組,但是通過棧操作來訪問。所謂操作數(shù)是那些被指令操作的數(shù)據(jù)。當(dāng)需要對參數(shù)操作時如a=b+c,就將即將被操作的參數(shù)壓棧,如將b 和c 壓棧,然后由操作指令將它們彈出,并執(zhí)行操作。虛擬機(jī)將操作數(shù)棧作為工作區(qū)。
(3):幀數(shù)據(jù)區(qū)處理常量池解析,異常處理等

 

1.3 java堆 

      java的堆是一個運(yùn)行時的數(shù)據(jù)區(qū),用來存儲數(shù)據(jù)的單元,存放通過new關(guān)鍵字新建的對象數(shù)組,對象從中分配內(nèi)存。
      在堆中聲明的對象,是不能直接訪問的,必須通過在棧中聲明的指向該引用的變量來調(diào)用。引用變量就相當(dāng)于是為數(shù)組或?qū)ο笃鸬囊粋€名稱,以后就可以在程序中使用棧中的引用變量來訪問堆中的數(shù)組或?qū)ο蟆?/font>
   

     由此我們可以知道,引用類型變量和對象的區(qū)別: 

聲明的對象是在堆內(nèi)存中初始化的, 真正用來存儲數(shù)據(jù)的。不能直接訪問。

引用類型變量是保存在棧當(dāng)中的,一個用來引用堆中對象的符號而已(指針)。


堆與棧的比較
JAVA堆與棧都是用來存放數(shù)據(jù)的,那么他們之間到底有什么差異呢?既然棧也能存放數(shù)據(jù),為什么還要設(shè)計堆呢?


1.從存放數(shù)據(jù)的角度:

      前面我們已經(jīng)說明:

      棧中存放的是基本類型的變量or引用類型的變量

       堆中存放的是對象or數(shù)組對象.

       在棧中,引用變量的大小為32位,基本類型為1-8個字節(jié)。
       但是對象的大小和數(shù)組的大小是動態(tài)的,這也決定了堆中數(shù)據(jù)的動態(tài)性,因?yàn)樗窃谶\(yùn)行時動態(tài)分配內(nèi)存的,生存期也不必在編譯時確定,Java 的垃圾收集器會自動收走這些不再使用的數(shù)據(jù)。

 

2.從數(shù)據(jù)共享的角度:

    1).在單個線程類,棧中的數(shù)據(jù)可共享

    例如我們定義:

Java代碼
  1. int a=3;   
  2. int b=3;  

    編譯器先處理int a = 3;首先它會在棧中創(chuàng)建一個變量為a 的引用,然后查找棧中是否有3 這個值,如果沒找到,就將3 存放進(jìn)來,然后將a 指向3。接著處理int b = 3;在創(chuàng)建完b 的引用變量后,因?yàn)樵跅V幸呀?jīng)有3這個值,便將b 直接指向3。這樣,就出現(xiàn)了a 與b 同時均指向3的情況。

    而如果我們定義: 

Java代碼
  1. Integer a=new Integer(3);//(1)   
  2. Integer b=new Integer(3);//(2)  

   這個時候執(zhí)行過程為:在執(zhí)行(1)時,首先在棧中創(chuàng)建一個變量a,然后在堆內(nèi)存中實(shí)例化一個對象,并且將變量a指向這個實(shí)例化的對象。在執(zhí)行(2)時,過程類似,此時,在堆內(nèi)存中,會有兩個Integer類型的對象。 

 

    2).在進(jìn)程的各個線程之間,數(shù)據(jù)的共享通過堆來實(shí)現(xiàn)

        例:那么,在多線程開發(fā)中,我們的數(shù)據(jù)共享又是怎么實(shí)現(xiàn)的呢?

 

  如圖所示,堆中的數(shù)據(jù)是所有線程棧所共享的,我們可以通過參數(shù)傳遞,將一個堆中的數(shù)據(jù)傳入各個棧的工作內(nèi)存中,從而實(shí)現(xiàn)多個線程間的數(shù)據(jù)共享

(多個進(jìn)程間的數(shù)據(jù)共享則需要通過網(wǎng)絡(luò)傳輸了。) 

 

3.從程序設(shè)計的的角度:

從軟件設(shè)計的角度看,JVM棧代表了處理邏輯,而JVM堆代表了數(shù)據(jù)。這樣分開,使得處理邏輯更為清晰。分而治之的思想。這種隔離、模塊化的思想在軟件設(shè)計的方方面面都有體現(xiàn)。


4.值傳遞和引用傳遞的真相

有了以上關(guān)于棧和堆的種種了解后,我們很容易就可以知道值傳遞和引用傳遞的真相:

 

1.程序運(yùn)行永遠(yuǎn)都是在JVM棧中進(jìn)行的,因而參數(shù)傳遞時,只存在傳遞基本類型和對象引用的問題。不會直接傳對象本身。

但是傳引用的錯覺是如何造成的呢?

在運(yùn)行JVM棧中,基本類型和引用的處理是一樣的,都是傳值,所以,如果是傳引用的方法調(diào)用,也同時可以理解為“傳引用值”的傳值調(diào)用,即引用的處理跟基本類型是完全一樣的。

但是當(dāng)進(jìn)入被調(diào)用方法時,被傳遞的這個引用的值,被程序解釋(或者查找)到JVM堆中的對象,這個時候才對應(yīng)到真正的對象。

如果此時進(jìn)行修改,修改的是引用對應(yīng)的對象,而不是引用本身,即:修改的是JVM堆中的數(shù)據(jù)。所以這個修改是可以保持的了。

 

 

最后:

從某種意義上來說對象都是由基本類型組成的。 

 

可以把一個對象看作為一棵樹,對象的屬性如果還是對象,則還是一顆樹(即非葉子節(jié)點(diǎn)),基本類型則為樹的葉子節(jié)點(diǎn)。程序參數(shù)傳遞時,被傳遞的值本身都是不能進(jìn)行修改的,但是,如果這個值是一個非葉子節(jié)點(diǎn)(即一個對象引用),則可以修改這個節(jié)點(diǎn)下面的所有內(nèi)容。 


其實(shí),面向?qū)ο蠓绞降某绦蚺c以前結(jié)構(gòu)化的程序在執(zhí)行上沒有任何區(qū)別。

面向?qū)ο蟮囊耄皇?/span>改變了我們對待問題的思考方式,而更接近于自然方式的思考。

當(dāng)我們把對象拆開,其實(shí)對象的屬性就是數(shù)據(jù),存放在JVM堆中;而對象的行為(方法),就是運(yùn)行邏輯,放在JVM棧中。我們在編寫對象的時候,其實(shí)即編寫了數(shù)據(jù)結(jié)構(gòu),也編寫的處理數(shù)據(jù)的邏輯。 

 

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服