三分鐘理解Java中字串(String)的儲存和賦值原理
可能很多java的初學者對String的儲存和賦值有迷惑,以下是一個很簡單的測試用例,你只需要花幾分鐘時間便可理解。
1.在看例子之前,確保你理解以下幾個術語:
棧:由JVM分配區域,用於儲存執行緒執行的動作和資料引用。棧是一個執行的單位,Java中一個執行緒就會相應有一個執行緒棧與之對應。
堆:由JVM分配的,用於儲存物件等資料的區域。
常量池:在編譯的階段,在堆中分配出來的一塊儲存區域,用於儲存顯式的String,float或者integer.例如String str="abc"; abc這個字串是顯式宣告,所以儲存在常量池。
2.看這個例子,用JDK5+junit4.5寫的例子,完全通過測試
importstatic org.junit.Assert.assertSame;
import org.junit.Test;
/**
* @author Heis
*
*/publicclass StringTest{
@Test
publicvoid testTheSameReference1(){
String str1="abc";
String str2="abc";
String str3="ab"+"c";
String str4
//str1和str2引用自常量池裡的同一個string物件 assertSame(str1,str2);
//str3通過編譯優化,與str1引用自同一個物件 assertSame(str1,str3);
//str4因為是在堆中重新分配的另一個物件,所以它的引用與str1不同 assertNotSame(str1,str4);
}
}
- 第一個斷言很好理解,因為在編譯的時候,"abc"被儲存在常量池中,str1和str2的引用都是指向常量池中的"abc"。所以str1和str2引用是相同的。
- 第二個斷言是由於編譯器做了優化,編譯器會先把字串拼接,再在常量池中查詢這個字串是否存在,如果存在,則讓變數直接引用該字串。所以str1和str3引用也是相同的。
- str4的物件不是顯式賦值的,編譯器會在堆中重新分配一個區域來儲存它的物件資料。所以str1和str4的引用是不一樣的。
另一種說法,求大神指點
JVM記憶體分四種: 1、棧區(stacksegment)—由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,具體方法執行結束之後,系統自動釋放JVM記憶體資源 2、堆區(heapsegment)—一般由程式設計師分配釋放,存放由new建立的物件和陣列,jvm不定時檢視這個物件,如果沒有引用指向這個物件就回收 3、靜態區(datasegment)—存放全域性變數,靜態變數和字串常量,不釋放 4、程式碼區(codesegment)—存放程式中方法的二進位制程式碼,而且是多個物件共享一個程式碼空間區域 在方法(程式碼塊)中定義一個變數時,java就在棧中為這個變數分配JVM記憶體空間,當超過變數的作用域後,java會自動釋放掉為該變數所分配的JVM記憶體空間;在堆中分配的JVM記憶體由java虛擬機器的自動垃圾回收器來管理,堆的優勢是可以動態分配JVM記憶體大小,生存期也不必事先告訴編譯器,因為它是在執行時動態分配JVM記憶體的。缺點就是要在執行時動態分配JVM記憶體,存取速度較慢;棧的優勢是存取速度比堆要快,缺點是存在棧中的資料大小與生存期必須是確定的無靈活性。 ◆java堆由Perm區和Heap區組成,Heap區則由Old區和New區組成,而New區又分為Eden區,From區,To區,Heap={Old+NEW={Eden,From,To}},見圖1所示。 Heap區分兩大塊,一塊是NEWGeneration,另一塊是OldGeneration.在NewGeneration中,有一個叫Eden的空間,主要是用來存放新生的物件,還有兩個SurvivorSpaces(from,to),它們用來存放每次垃圾回收後存活下來的物件。在OldGeneration中,主要存放應用程式中生命週期長的JVM記憶體物件,還有個PermanentGeneration,主要用來放JVM自己的反射物件,比如類物件和方法物件等。 在NewGeneration塊中,垃圾回收一般用Copying的演算法,速度快。每次GC的時候,存活下來的物件首先由Eden拷貝到某個SurvivorSpace,當SurvivorSpace空間滿了後,剩下的live物件就被直接拷貝到OldGeneration中去。因此,每次GC後,EdenJVM記憶體塊會被清空。在OldGeneration塊中,垃圾回收一般用mark-compact的演算法,速度慢些,但減少JVM記憶體要求. 垃圾回收分多級,0級為全部(Full)的垃圾回收,會回收OLD段中的垃圾;1級或以上為部分垃圾回收,只會回收NEW中的垃圾,JVM記憶體溢位通常發生於OLD段或Perm段垃圾回收後,仍然無JVM記憶體空間容納新的Java物件的情況。 JVM呼叫GC的頻度還是很高的,主要兩種情況下進行垃圾回收:當應用程式執行緒空閒;另一個是JVM記憶體堆不足時,會不斷呼叫GC,若連續回收都解決不了JVM記憶體堆不足的問題時,就會報outofmemory錯誤。因為這個異常根據系統執行環境決定,所以無法預期它何時出現。 根據GC的機制,程式的執行會引起系統執行環境的變化,增加GC的觸發機會。為了避免這些問題,程式的設計和編寫就應避免垃圾物件的JVM記憶體佔用和GC的開銷。顯示呼叫System.GC()只能建議JVM需要在JVM記憶體中對垃圾物件進行回收,但不是必須馬上回收,一個是並不能解決JVM記憶體資源耗空的局面,另外也會增加GC的消耗。 ◆當一個URL被訪問時,JVM記憶體區域申請過程如下: A.JVM會試圖為相關Java物件在Eden中初始化一塊JVM記憶體區域 B.當Eden空間足夠時,JVM記憶體申請結束。否則到下一步 C.JVM試圖釋放在Eden中所有不活躍的物件(這屬於1或更高階的垃圾回收),釋放後若Eden空間仍然不足以放入新物件,則試圖將部分Eden中活躍物件放入Survivor區 D.Survivor區被用來作為Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的物件會被移到Old區,否則會被保留在Survivor區 E.當OLD區空間不夠時,JVM會在OLD區進行完全的垃圾收集(0級) F.完全垃圾收集後,若Survivor及OLD區仍然無法存放從Eden複製過來的部分物件,導致JVM無法在Eden區為新物件建立JVM記憶體區域,則出現"outofmemory錯誤"
相關推薦
三分鐘理解Java中字串(String)的儲存和賦值原理
可能很多java的初學者對String的儲存和賦值有迷惑,以下是一個很簡單的測試用例,你只需要花幾分鐘時間便可理解。 1.在看例子之前,確保你理解以下幾個術語: 棧:由JVM分配區域,用於儲存執行緒執行的動作和資料引用。棧是一個執行的單位,Java中一個執行緒就會相應有一個
Java中字串定義,初始化,賦值為null的區別
1、概述:字串定義 只定義不分配記憶體空間,不做任何操作;字串初始化 兩種方式直接等號賦值,用new初始化,直接等號賦值放入記憶體池,其它變數也可以引用;new初始化分配記憶體空間,不可引用;字串賦值為
java中package(包)的使用理解
java中package(包)的使用理解 2017年02月05日 02:30:08 FengGLA 閱讀數:17755 標籤: java 更多 個人分類: java學習筆記 版權宣告:本文為博主原創文章,未經博主允許不得轉載。
十分鐘理解 Java 中的動態代理
一、概述 1. 什麼是代理 我們大家都知道微商代理,簡單地說就是代替廠家賣商品,廠家“委託”代理為其銷售商品。關於微商代理,首先我們從他們那裡買東西時通常不知道背後的廠家究竟是誰,也就是說,“委託者”對我們來說是不可見的;其次,微商代理主要以朋友圈的人為目標客戶,這就相當於為廠家做了一次對客
# Java中遍歷Object的屬性和屬性值,並以String形式返回||toString()一個物件Object||將一個物件轉化為字串String
Java中遍歷Object的屬性和屬性值,並以String形式返回||toString()一個物件Object||將一個物件轉化為字串String 1.關注每個屬性組 //用List<Map<String, String>>
深入理解Java:註解(Annotation)--註解處理器
fault this urn 復制代碼 lena ide set java lec 深入理解Java:註解(Annotation)--註解處理器 如果沒有用來讀取註解的方法和工作,那麽註解也就不會比註釋更有用處了。使用註解的過程中,很重要的一部分就是創建於
Java中long(Long)與int(Integer)之間的轉換(轉)
轉化 string long tar str 基礎數據類型 ava detail 參考 一、將long型轉化為int型,這裏的long型是基礎類型: long a = 10; int b = (int)a; 二、將Long型轉換為int型,這裏
深入理解Java的註解(Annotation):註解處理器(3)
isp 通過反射 out peid 擴展 .cn 自定義註解 忽略 否則 如果沒有用來讀取註解的方法和工作,那麽註解也就不會比註釋更有用處了。使用註解的過程中,很重要的一部分就是創建於使用註解處理器。Java SE5擴展了反射機制的API,以幫助程序員快速的構造自定義註解處
深入理解Java虛擬機(筆記)
包括 指針 思想 創建 區域 算法; 很多 由於 線程安全 內存分配: 為對象分配內存有兩種方式,第一種是“指針碰撞”,也就是把內存分為兩邊,一邊是已使用區域,另一邊是未分配區域,分界線用指針記錄,當要分配內存時,只需把指針向未分配區域移動需要的空間即可,通常compa
Java中List<E>對象賦值問題(深淺拷貝)
不能 沒有 add size for .get one util contains Java中List<E>對象賦值操作問題 業務需求是:取2個集合中的交集對象並返回。如下代碼,busMap中key值和stocks中Map中的key值相等的對象則返回繼續操作,
java中異常(Exception)的定義,意義和用法。舉例
use 詳情 put 視頻下載 ati itl url index ring 1.異常(Exception)的定義,意義和用法 (視頻下載) (全部書籍) 我們先給出一個例子,看看異常有什麽用? 例:1.1-本章源碼 public class Test { publi
Javascript的字串(String)操作學習
1、bold() 方法用於把字串顯示為粗體。語法: stringObject.bold() 如下,對str進行bold操作之後,實際上時對這個字串加了<b>標籤,在文件中將以粗體進行展示 let str = 'Hello world' let str1 = str
java中介面(interface)及使用方法和注意事項
1、介面:一種把類抽象的更徹底,接口裡只能包含抽象方法的“特殊類”。介面不關心類的內部狀態資料,定義的是一批類所遵守的規範。(它只規定這批類裡必須提供某些方法,提供這些方法就可以滿足實際要求)。 在JAVA程式語言中是一個抽象型別,是抽象方法的集合,介面通常以interface來宣告。一個類通過
java學習筆記(二)parseInt和valueOf 以及字串+和StringBuilder的區別
parseInt和valueOf 我們平時應該都用過或者見過parseInt和valueOf這兩個方法。一般我們是想把String型別的字元數字轉成int型別。從這個功能層面來說,這兩個方法都一樣,都可以勝任這個功能。 但是,我們進入原始碼,看下Integer類下這兩個方法 pars
深入理解java虛擬機器(六)位元組碼指令簡介
Java虛擬機器指令是由(佔用一個位元組長度、代表某種特定操作含義的數字)操作碼Opcode,以及跟隨在其後的零至多個代表此操作所需引數的稱為運算元 Operands 構成的。由於Java虛擬機器是面向運算元棧而不是暫存器的架構,所以大多數指令都只有操作碼,而沒有運算元。 位元組碼指令集是一種具有鮮明特點、
深入理解java虛擬機器(一)java虛擬機器的記憶體區域
一、 java虛擬機器記憶體區域主要有:方法區、堆、虛擬機器棧、本地方方法棧、程式計數器 按照執行緒私有和共有來分:執行緒私有的有--程式計數器,虛擬機器棧,本地方法棧。共有的有--本地方法區,堆 1、程式計數器:主要功能是控制程式
Redis儲存結構之字串(String)
Redis中的字串是一個位元組序列。Redis中的字串是二進位制安全的,這意味著它們的長度不由任何特殊的終止字元決定。因此,可以在一個字串中儲存高達512兆位元組的任何內容。 hget、hset、hgetall get、set、incr、decr、mget APPEND
Java中TimeZone(時區)類的簡單使用
package com.wk.time import java.util.TimeZone; public class LocaleTimeZone { public static void main(String[] args) { TimeZone zone =
深入理解Java虛擬機器(5)Java記憶體模型
深入理解Java虛擬機器(5)Java記憶體模型 Java記憶體模型 主記憶體和工作記憶體 volatile關鍵字 long與double型別的特殊規則 synchronized關鍵字 Java記憶體模
java中實用類(二)
一、String類 1.在java中String類比較特殊,它是一種引用資料型別,位於java.lang包中。 2.String類的常用方法 (1)length()方法,是求字串的長度 String str="abcdefg"; int s=str.length(); //注意,