java 常量 內存分配_Java內存分配之堆、棧和常量池

寄存器:最快的存儲區,位于不同于其他存儲區的地方——處理器內部。寄存器的數量極其有限,所以寄存器由編譯器根據需求 進行分配。你不能直接控制,也不能在程序中感覺到寄存器存在的任何跡象。

棧:存放基本類型的數據和對象的引用,但對象本身不存放在棧中,而是存放在堆中

堆:一種通用性的內存池(也存在于RAM中),用于存放所以的JAVA對象。堆不同于堆棧的好處是:編譯器不需要知道要從堆里分配多少存儲區域,也不必知道存儲的數據在堆里存活多長時間。因此,在堆里分配存儲有很大的靈活性。當你需要創建一個對象的時候,只需要new寫一行簡單的代碼,當執行這行代碼時,會自動在堆里進行存儲分配。當然,為這種靈活性必須要付出相應的代碼。用堆進行存儲分配比用堆棧進行存儲存儲需要更多的時間。存放用new產生的數據

靜態域:存放在對象中用static定義的靜態成員

常量池:存放常量

非RAM(隨機存取存儲器)存儲:硬盤等永久存儲空間。如果數據完全存活于程序之外,那么它可以不受程序的任何控制,在程序沒有運行時也可以存在。 這里我們主要關心棧,堆和常量池,對于棧和常量池中的對象可以共享,對于堆中的對象不可以共享。棧中的數據大小和生命周期是可以確定的,當沒有引用指向數據時,這個數據就會消失。堆中的對象的由垃圾回收器負責回收,因此大小和生命周期不需要確定,具有很大的靈活性。

Java內存分配中的棧

在函數中定義的一些基本類型的變量數據和對象的引用變量都在函數的棧內存中分配。當在一段代碼塊定義一個變量時,Java就在棧中為這個變量分配內存空間,當該變量退出該作用域后,Java會自動釋放掉為該變量所分配的內存空間,該內存空間可以立即被另作他用。

Java內存分配中的堆

堆內存用來存放由new創建的對象和數組。 在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。在堆中產生了一個數組或對象后,還可以 在棧中定義一個特殊的變量,讓棧中這個變量的取值等于數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量。引用變量就相當于是為數組或對象起的一個名稱,以后就可以在程序中使用棧中的引用變量來訪問堆中的數組或對象。引用變量就相當于是為數組或者對象起的一個名稱。

常量池 (constant pool)

常量池指的是在編譯期被確定,并被保存在已編譯的.class文件中的一些數據。除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數組)的*常量值(final)*還包含一些以文本形式出現的符號引用,比如:

類和接口的全限定名;

字段的名稱和描述符;

方法和名稱和描述符。

虛擬機必須為每個被裝載的類型維護一個常量池。常量池就是該類型所用到常量的一個有序集和,包括直接常量(string,integer和 floating point常量)和對其他類型,字段和方法的符號引用。

對于String常量,它的值是在常量池中的。而JVM中的常量池在內存當中是以表的形式存在的, 對于String類型,有一張固定長度的CONSTANT_String_info表用來存儲文字字符串值,注意:該表只存儲文字字符串值,不存儲符號引 用。說到這里,對常量池中的字符串值的存儲位置應該有一個比較明了的理解了。

在程序執行的時候,常量池會儲存在Method Area,而不是堆中。

堆與棧

Java的堆是一個運行時數據區,類的(對象從中分配空間。這些對象通過new、newarray、 anewarray和multianewarray等指令建立,它們不需要程序代碼來顯式的釋放。堆是由垃圾回收來負責的,堆的*優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,因為它是在運行時動態分配內存的*,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由于要在運行時動態 分配內存,存取速度較慢。

棧的優勢是,存取速度比堆要快,僅次于寄存器,棧數據可以共享。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。棧中主要存放一些基本類型的變量數據(int, short, long, byte, float, double, boolean, char)和對象句柄(引用)。

字符串內存分配

對于字符串,其對象的引用都是存儲在棧中的,如果是編譯期已經創建好(直接用雙引號定義的)的就存儲在常量池中,如果是運行期(new出來的)才能確定的就存儲在堆中。對于equals相等的字符串,在常量池中永遠只有一份,在堆中有多份。

這里我們主要關心棧,堆和常量池,對于棧和常量池中的對象可以共享,對于堆中的對象不可以共享。棧中的數據大小和生命周期是可以確定的,當沒有引用指向數據時,這個數據就會消失。堆中的對象的由垃圾回收器負責回收,因此大小和生命周期不需要確定,具有很大的靈活性。

String s1 = "china";

String s2 = "china";

String s3 = "china";

String ss1 = new String("china");

String ss2 = new String("china");

String ss3 = new String("china");

930789a36c3ee284764abc332b2df268.png

這里解釋一下黃色這3個箭頭,對于通過new產生一個字符串(假設為“china”)時,會先去常量池中查找是否已經有了“china”對象,如果沒有則在常量池中創建一個此字符串對象,然后堆中再創建一個常量池中此”china”對象的拷貝對象。

這也就是有道面試題:Strings=newString(“xyz”);產生幾個對象?一個或兩個,如果常量池中原來沒有”xyz”,就是兩個。

存在于.class文件中的常量池,在運行期被JVM裝載,并且可以擴充。String的 intern()方法就是擴充常量池的 一個方法;當一個String實例str調用intern()方法時,Java 查找常量池中是否有相同Unicode的字符串常量,如果有,則返回其的引用,如果沒有,則在常量池中增加一個Unicode等于str的字符串并返回它的引用

String s0= "kvill";

String s1=new String("kvill");

String s2=new String("kvill");

System.out.println( s0==s1 );

s1.intern();

s2=s2.intern(); //把常量池中"kvill"的引用賦給s2

System.out.println( s0==s1);

System.out.println( s0==s1.intern() );

System.out.println( s0==s2 );false

false

true

true

String常量池問題的幾個例子:

【1】

String a = "ab";

String bb = "b";

String b = "a" + bb;

System.out.println((a == b)); //result = false

【2】

String a = "ab";

final String bb = "b";

String b = "a" + bb;

System.out.println((a == b)); //result = true

【3】

String a = "ab";

final String bb = getBB();

String b = "a" + bb;

System.out.println((a == b)); //result = false

private static String getBB() {

return "b";

}

分析:

【1】中,JVM對于字符串引用,由于在字符串的"+"連接中,有字符串引用存在,而引用的值在程序編譯期是無法確定的,即"a" + bb無法被編譯器優化,只有在程序運行期來動態分配并將連接后的新地址賦給b。所以上面程序的結果也就為false。

【2】和【1】中唯一不同的是bb字符串加了final修飾,對于final修飾的變量,它在編譯時被解析為常量值的一個本地拷貝存儲到自己的常量池中或嵌入到它的字節碼流中。所以此時的"a" + bb和"a" + "b"效果是一樣的。故上面程序的結果為true。

【3】JVM對于字符串引用bb,它的值在編譯期無法確定,只有在程序運行期調用方法后,將方法的返回值和"a"來動態連接并分配地址為b,故上面程序的結果為false。

結論:

字符串是一個特殊包裝類,其引用是存放在棧里的,而對象內容必須根據創建方式不同定(常量池和堆).有的是編譯期就已經創建好,存放在字符串常量池中,而有的是運行時才被創建使用new關鍵字,存放在堆中。

基礎類型的變量和常量在內存中的分配

對于基礎類型的變量和常量,變量和引用存儲在棧中,常量存儲在常量池中。

int i1 = 9;

int i2 = 9;

int i3 = 9;

final int INT1 = 9;

final int INT2 = 9;

final int INT3 = 9;

efadda87c1e7a91976be48bf1329de43.png

編譯器先處理int i1 = 9;首先它會在棧中創建一個變量為i1的引用,然后查找棧中是否有9這個值,如果沒找到,就將9存放進來,然后將i1指向9。接著處理int i2 = 9;在創建完i2的引用變量后,因為在棧中已經有9這個值,便將i2直接指向9。這樣,就出現了i1與i2同時均指向9的情況。最后i3也指向這個9。

成員變量和局部變量在內存中的分配

對于成員變量和局部變量:成員變量就是方法外部,類的內部定義的變量;局部變量就是方法或語句塊內部定義的變量。局部變量必須初始化。?形式參數是局部變量,局部變量的數據存在于棧內存中。棧內存中的局部變量隨著方法的消失而消失。?成員變量存儲在堆中的對象里面,由垃圾回收器負責回收

class BirthDate {

private int day;

private int month;

private int year;

public BirthDate(int d, int m, int y) {

day = d;

month = m;

year = y;

}

// 省略get,set方法………

}

public class Test {

public static void main(String args[]) {

int date = 9;

Test test = new Test();

test.change(date);

BirthDate d1 = new BirthDate(7, 7, 1970);

}

public void change(int i) {

i = 1234;

}

}

ed31883a57bd08b75e2ab3515d3903d8.png

對于以上這段代碼,date為局部變量,i,d,m,y都是形參為局部變量,day,month,year為成員變量。下面分析一下代碼執行時候的變化:

main方法開始執行:int date = 9; date局部變量,基礎類型,引用和值都存在棧中。

Test test = new Test();test為對象引用,存在棧中,對象(new Test())存在堆中。

test.change(date); i為局部變量,引用和值存在棧中。當方法change執行完成后,i就會從棧中消失。

BirthDate d1= new BirthDate(7,7,1970); d1為對象引用,存在棧中,對象(new BirthDate())存在堆中,其中d,m,y為局部變量存儲在棧中,且它們的類型為基礎類型,因此它們的數據也存儲在棧中。day,month,year為成員變量,它們存儲在堆中(new BirthDate()里面)。當BirthDate構造方法執行完之后,d,m,y將從棧中消失。

main方法執行完之后,date變量,test,d1引用將從棧中消失,new Test(), new BirthDate()將等待垃圾回收。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/272782.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/272782.shtml
英文地址,請注明出處:http://en.pswp.cn/news/272782.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

三種SQLServer分頁查詢語句筆記

作為程序員來說,與數據庫打交道是十分頻繁的分頁查詢是一個開發者必須掌握的基本知識點,目前整理了下面三種SQLServer分頁查詢語句的寫法,僅供參考。一、Top Not IN 方式(查詢靠前的數據較快)語法格式:sele…

sqlserver2008r2安裝

轉載于:https://www.cnblogs.com/sprinng/p/4932739.html

JQuery七個常犯的錯誤

1、 亂用選擇器JQuery選擇器調用代價很大,反復調用效率更低。應采用緩存對象的方法或采用鏈式調用的方式。//錯誤的寫法$("#button").click(function(){ $(#list li).addClass(strong); $(#list li).css(color,red);});//正確的寫法$("#button…

java流讀取xml_使用FileInputStream(用于Java)讀取XML文件?

這是交易.對于我的項目,我必須使用Java和XStream對隨機樹進行序列化和反序列化.我的老師制作了Tree / RandomTree算法,所以我不必擔心.我不知道該怎么做是這樣的:我使用FileInputStream來讀/寫我序列化和反序列化的xml文件,但是當我反序列化時,我不知道用于讀取文件…

后臺尋路系統的大體思路與流程

總的思路就是: 1, 通過前臺unity的navigation的的接口: 獲得頂點和三角形集合數據 2, 將前臺的mesh數據轉換成標準的obj格式數據 3. 強obj mesh數據經過一系列轉換和優化, 生成recastnavigation插件尋路模塊detour需要的導航數據 故制作了工具MakeNavmeshData生成detour需要的…

關于WCF、WebAPI、WCFREST、WebService之間的區別總結

在.net平臺下,有大量的技術讓你創建一個HTTP服務,像Web Service,WCF,現在又出了Web API。在.net平臺下,你有很多的選擇來構建一個HTTP Services。我分享一下我對Web Service、WCF以及Web API的看法。一、Web Service1、…

java 程序是由什么組成的 java_從零開始的JAVA -2. java程序的構成及命名規則

1.public classYD2.{3. public static voidmain (string args[ ])4. {5. System.out.println("我是一名學習JAVA的新人!");6. }7.}第一行 public 代表這是一個公共類(可省略) class 是聲明一個類,在他后面的YD 就是類名(類名可以隨意寫)第二行…

你應該知道的jQuery技巧【收藏】

jQuery的存在,讓學習前端開發的人感到前端越來越容易入門了,用簡單的幾行代碼就可以實現需求,但是,你真的會用jQuery么,當代碼運行 后無法看到自己預期的效果,是不是覺得jQuery出了問題,其實&am…

LINQ表達式用法整理

收集一些Linq表達式中的一些比較常用的寫法,希望能給大家工作當中帶來一些便利。1. Where子句條件過濾結果集型(集合數據使用這種,譬如數組、列表數據,同樣適用于Datatable等多列數據集)類SQL語句的寫法,對…

Eclipse is running in a JRE, but a JDK is required 解決方法(轉)

轉自:http://comeonbabye.iteye.com/blog/1186239 安裝Maven后每次啟動出現警告信息: Eclipse is running in a JRE, but a JDK is requiredSome Maven plugins may not work when importing projects or updating source folders. 分兩步解決問題: 1. 檢查Eclipse正…

java線程歸并排序_Java-歸并排序 - FeanLau的個人空間 - OSCHINA - 中文開源技術交流社區...

public class MergeSort {static int number0;public static void main(String[] args) {int[] a {26, 5, 98, 108, 28, 99, 100, 56, 34, 1 };printArray("排序前:",a);MergeSort(a);printArray("排序后:",a);}private static voi…

收集一些優秀的DoNet開源項目

Paste_Image.pngJson.NEThttp://json.codeplex.com/ Json.Net是一個讀寫Json效率比較高的.Net框架.Json.Net 使得在.Net環境下使用Json更加簡單。通過Linq To JSON可以快速的讀寫Json,通過JsonSerializer可以序列化你的.Net對象。讓你輕松實現.Net中所有類型(對象,基…

git初探

1 Linux下Git和GitHub環境的搭建 第一步: 安裝Git,使用命令 “sudo apt-get install git” 第二步: 到GitHub上創建GitHub帳號 第三步: 生成ssh key,使用命令 “ssh-keygen -t rsa -C "your_emailyouremail.com&q…

java編程思想 初始化_《java編程思想》_第五章_初始化與清理

初始化和清理是涉及安全的兩個問題,java中采用了構造器,并額外提供了“垃圾回收器”,對于不再使用的內存資源,垃圾回收器能自動將其釋放。一、用構造器確保初始化java中,通過提供構造器,類的設計者可以確保…

OkHttp 上手

OkHttp 上手 優點 快、節省帶寬。支持 HTTP/2 和 SPDY。HTTP/2 和 SPDY 允許對同一個主機的所有請求,使用一個 socket。如果不支持 SPDY 的話,可以用連接池減少請求等待時間。GZIP 縮小傳輸大小。緩存響應(response ca…

關于Net開發中一些SQLServer性能優化的建議

一、 ExecuteNonQuery和ExecuteScalar 對數據的更新不需要返回結果集,建議使用ExecuteNonQuery。由于不返回結果集可省掉網絡數據傳輸。它僅僅返回受影響的行數。如果只需更新數據用ExecuteNonQuery性能的開銷比較小。 ExecuteScalar它只返回結果集中第一行的第一列…

jstl mysql_java – jsp jstl sql與mysql中的奇怪行為

在mysql中我有一個存儲過程,其中包含一個sql:select firstname as i_firstname , lastname as i_lastname from roleuserwhere user_id uid ;我使用jstl代碼來獲取值: –call sp_select_username(?);${rows.i_firstname} ${rows.i_lastname}但是這個代…

C# 哈希表(Hashtable)用法筆記

一、什么是Hashtable?Hashtable 類代表了一系列基于鍵的哈希代碼組織起來的鍵/值對。它使用鍵來訪問集合中的元素。當您使用鍵訪問元素時,則使用哈希表,而且您可以識別一個有用的鍵值。哈希表中的每一項都有一個鍵/值對。鍵用于訪問集合中的項…

轉: Div與table的區別

1&#xff1a;速度和加載方式方面的區別 div 和 table 的差異不是速度&#xff0c;而是加載方式&#xff0c;速度只能是指網絡速度&#xff0c;如果速度足夠快&#xff0c;是沒有差異的&#xff1a; div 的加載方式是即讀即加載&#xff0c;遇到 <div> 沒有遇到 </div…

你的工作是為了你自己!

1、無論為誰打工&#xff0c;要為自己學東西&#xff0c;客觀為公司創造價值。我自己當年&#xff0c;無論我在方正給國內企業工作&#xff0c;還是我在雅虎給外國人工作&#xff0c;我都跟別人最大的不一樣&#xff0c;我從來不覺得我在給他們打工&#xff0c;我真的可能是很有…