日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

了解栈内存堆内存

發(fā)布時(shí)間:2023/12/10 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 了解栈内存堆内存 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

由于 java 有垃圾回收機(jī)制,所以往往不太會(huì)去關(guān)注棧堆的內(nèi)存分配問題,直至OOM

一、了解棧堆概念

1、堆【存儲(chǔ)對象創(chuàng)建實(shí)例】

  • 程序開始運(yùn)行時(shí),JVM從OS獲取一些內(nèi)存,部分是堆內(nèi)存。堆內(nèi)存通常在存儲(chǔ)地址的底層,向上排列。
  • 堆是一個(gè)"運(yùn)行時(shí)"數(shù)據(jù)區(qū),類實(shí)例化的對象就是從堆上去分配空間的;
  • 在堆上分配空間是通過"new"等指令建立的,堆是動(dòng)態(tài)分配的內(nèi)存大小,生存期也不必事先告訴編譯器;
  • 與C++不同的是,Java自動(dòng)管理堆和棧,垃圾回收器可以自動(dòng)回收不再使用的堆內(nèi)存;
  • 缺點(diǎn)是,由于要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,所以內(nèi)存的存取速度較慢。
  • 2、棧【存放基本類型和引用類型】

  • 先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),通常用于保存方法中的參數(shù),局部變量;
  • 在java中,所有基本類型(short,int, long, byte, float, double,boolean, char)和引用類型的變量都在棧中存儲(chǔ);
  • 棧中數(shù)據(jù)的生存空間一般在當(dāng)前scopes內(nèi)(由{…}括起來的區(qū)域;
  • 棧的存取速度比堆要快,僅次于直接位于CPU中的寄存器;
  • 棧中的數(shù)據(jù)可以共享,多個(gè)引用可以指向同一個(gè)地址;
  • 缺點(diǎn)是,棧的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。
  • 3、總結(jié)

  • Java堆內(nèi)存是操作系統(tǒng)分配給JVM的內(nèi)存的一部分。
  • 當(dāng)我們創(chuàng)建對象時(shí),它們存儲(chǔ)在Java堆內(nèi)存中。
  • 你可以通過用JVM的命令行選項(xiàng) -Xms, -Xmx, -Xmn來調(diào)整Java堆空間的大小。
  • 棧中存放的基本類型數(shù)據(jù):short,int, long, byte, float, double,boolean, char
  • 只要采用 new 的形式創(chuàng)建對象,那么就存儲(chǔ)在 java 堆內(nèi)存中。
  • 二、棧中的數(shù)據(jù)存儲(chǔ)

    1、基本類型數(shù)據(jù)存儲(chǔ)

    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的情況。

    所以 a == b true

    2、包裝類數(shù)據(jù)存儲(chǔ)

    如Integer, Double, String等將相應(yīng)的基本數(shù)據(jù)類型包裝起來的類。
    這些類數(shù)據(jù)全部存在于堆中,Java用new()語句來顯示地告訴編譯器,在運(yùn)行時(shí)才根據(jù)需要?jiǎng)討B(tài)創(chuàng)建,因此比較靈活,但缺點(diǎn)是要占用更多的時(shí)間。

    以String為例

    String是一個(gè)特殊的包裝類數(shù)據(jù)。即可以用String str = new String("abc");的形式來創(chuàng)建,也可以用String str = "abc";的形式來創(chuàng)建。
    前者是規(guī)范的類的創(chuàng)建過程,即在Java中,一切都是對象,而對象是類的實(shí)例,全部通過new()的形式來創(chuàng)建。

    那為什么在String str = "abc";中,并沒有通過new()來創(chuàng)建實(shí)例,是不是違反了上述原則?其實(shí)沒有。

    關(guān)于String str = "abc"的內(nèi)部工作。Java內(nèi)部將此語句轉(zhuǎn)化為以下幾個(gè)步驟:

    • a、先定義一個(gè)名為str的對String類的對象引用變量:String str;
    • b、在棧中查找有沒有存放值為"abc"的地址,如果沒有,則開辟一個(gè)存放字面值為"abc"的地址,接著創(chuàng)建一個(gè)新的String類的對象O,并將O的字符串值指向這個(gè)地址,而且在棧中這個(gè)地址旁邊記下這個(gè)引用的對象O。如果已經(jīng)有了值為"abc"的地址,則查找對象O,并返回O的地址。
    • c、將str指向?qū)ο驩的地址。
       值得注意的是,通常String類中字符串值都是直接存值的。但像String str = "abc";這種場合下,其字符串值卻是保存了一個(gè)指向存在棧中數(shù)據(jù)的引用(即:String str = "abc";既有棧存儲(chǔ),又有堆存儲(chǔ))。

    為了更好地說明這個(gè)問題,我們可以通過以下的幾個(gè)代碼進(jìn)行驗(yàn)證。

    String?str1?=?"abc"; String?str2?=?"abc"; System.out.println(str1==str2);?//true

    只有在兩個(gè)引用都指向了同一個(gè)對象時(shí)才返回真值。str1與str2是否都指向了同一個(gè)對象)

    結(jié)果說明,JVM創(chuàng)建了兩個(gè)引用str1和str2,但只創(chuàng)建了一個(gè)對象,而且兩個(gè)引用都指向了這個(gè)對象。

    3、總結(jié)

    (1). 我們在使用諸如String str = "abc";的格式定義類時(shí),總是想當(dāng)然地認(rèn)為,我們創(chuàng)建了String類的對象str。

    擔(dān)心陷阱!對象可能并沒有被創(chuàng)建!唯一可以肯定的是,指向 String類的引用被創(chuàng)建了。
    至于這個(gè)引用到底是否指向了一個(gè)新的對象,必須根據(jù)上下文來考慮,除非你通過new()方法來顯要地創(chuàng)建一個(gè)新的對象。
    因此,更為準(zhǔn)確的說法是,我們創(chuàng)建了一個(gè)指向String類的對象的引用變量str,這個(gè)對象引用變量指向了某個(gè)值為"abc"的String類。
    清醒地認(rèn)識(shí)到這一點(diǎn)對排除程序中難以發(fā)現(xiàn)的bug是很有幫助的。

    (2). 使用String str = "abc";的方式,可以在一定程度上提高程序的運(yùn)行速度,因?yàn)镴VM會(huì)自動(dòng)根據(jù)棧中數(shù)據(jù)的實(shí)際情況來決定是否有必要?jiǎng)?chuàng)建新對象。
    而對于String str = new String("abc");的代碼,則一概在堆中創(chuàng)建新對象,而不管其字符串值是否相等,是否有必要?jiǎng)?chuàng)建新對象,從而加重了程序的負(fù)擔(dān)。

    (3). 由于String類的immutable性質(zhì)(因?yàn)榘b類的值不可修改),當(dāng)String變量需要經(jīng)常變換其值時(shí),應(yīng)該考慮使用StringBuffer類,以提高程序效率。

    4、實(shí)例

    String s = new String("abc") 創(chuàng)建了幾個(gè)對象?

    首先我們要明白兩個(gè)概念,引用變量和對象,對象一般通過new在堆中創(chuàng)建,s只是一個(gè)引用變量。

    答案2個(gè)。

    5、知識(shí)點(diǎn)

    我們可以用==判斷一下兩個(gè)引用變量是否指向了一個(gè)地址即一個(gè)對象

    總結(jié)

    以上是生活随笔為你收集整理的了解栈内存堆内存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。