http://www.cnblogs.com/Eason-S/p/5658230.htmlhtml
JAVA中,有六個不一樣的地方能夠存儲數據:java
1.寄存器:最快的存儲區,位於不一樣於其餘存儲區的地方——處理器內部。寄存器的數量極其有限,因此寄存器由編譯器根據需求進行分配。你不能直接控制,也不能在程序中感受到寄存器存在的任何跡象。面試
2. 棧:存放基本類型的變量數據和對象的引用。位於通用RAM中,但經過它的「堆棧指針」能夠從處理器哪裏得到支持。堆棧指針若向下移動,則分配新的內存;若向上移動,則釋放那些內存。這是一種快速有效的分配存儲方法,僅次於寄存器。建立程序時候,JAVA編譯器必須知道存儲在堆棧內全部數據的確切大小和生命週期,由於它必須生成 相應的代碼,以便上下移動堆棧指針。這一約束限制了程序的靈活性。安全
3. 堆:一種通用性的內存池(也存在於RAM中),用於存放因此的JAVA對象。堆不一樣於堆棧的好處是:編譯器不須要知道要從堆裏分配多少存儲區域,也沒必要知道存儲的數據在堆裏存活多長時間。所以,在堆裏分配存儲有很大的靈活性。當你須要建立一個對象的時候,只須要new寫一行簡單的代碼,當執行這行代碼時,會自動在堆裏進行存儲分配。固然,爲這種靈活性必需要付出相應的代碼。用堆進行存儲分配比用堆棧進行存儲存儲須要更多的時間。 jvm
4. 靜態域:存放靜態成員(static定義的) 。操作系統
5. 常量池:存放字符串常量和基本類型常量(public static final)。 常量值一般直接存放在程序代碼內部,這樣作是安全的,由於它們永遠不會被改變。.net
6. 非RAM存儲:硬盤等永久存儲空間。若是數據徹底存活於程序以外,那麼它能夠不受程序的任何控制,在程序沒有運行時也能夠存在。 設計
這裏咱們主要關心棧,堆和常量池,對於棧和常量池中的對象能夠共享,對於堆中的對象不能夠共享。指針
棧中的數據大小和生命週期是能夠肯定的,當沒有引用指向數據時,這個數據就會消失。堆中的對象的由垃圾回收器負責回收,所以大小和生命週期不須要肯定,具備很大的靈活性。 htm
(1)對於字符串:其對象的引用都是存儲在棧中的,若是是編譯期已經建立好(直接用雙引號定義的)的就存儲在常量池中,若是是運行期(new出來的)才能肯定的就存儲在堆中。對於equals相等的字符串,在常量池中永遠只有一份,在堆中有多份。
例如:
1 String s1 = "china"; 2 String s2 = "china"; 3 String s3 = "china"; 4 String ss1 = new String("china"); 5 String ss2 = new String("china"); 6 String ss3 = new String("china");
對於經過new產生一個字符串(假設爲」china」)時,會先去常量池中查找是否已經有了」china」對象,若是沒有則在常量池中建立一個此字符串對象,而後堆中再建立一個常量池中此」china」對象的拷貝對象。
這也就是有道面試題:String s = new String(「xyz」);產生幾個對象?答:一個或兩個,若是常量池中原來沒有」xyz」,就是兩個。
(2)對於基礎類型的變量和常量:變量和引用存儲在棧中,常量存儲在常量池中。
例如:
1 int i1 = 9; 2 int i2 = 9; 3 int i3 = 9; 4 public static final int INT1 = 9; 5 public static final int INT2 = 9; 6 public static final int INT3 = 9;
對於成員變量和局部變量:成員變量就是方法外部,類的內部定義的變量;局部變量就是方法或語句塊內部定義的變量。局部變量必須初始化。
形式參數是局部變量,局部變量的數據存在於棧內存中。棧內存中的局部變量隨着方法的消失而消失。
成員變量存儲在堆中的對象裏面,由垃圾回收器負責回收。
下面給出一個實例:
1 class BirthDate { 2 private int day; 3 private int month; 4 private int year; 5 public BirthDate(int d, int m, int y) { 6 day = d; 7 month = m; 8 year = y; 9 } 10 省略get,set方法……… 11 } 12 13 public class Test{ 14 public static void main(String args[]){ 15 int date = 9; 16 Test test = new Test(); 17 test.change(date); 18 BirthDate d1= new BirthDate(7,7,1970); 19 } 20 21 public void change(int i){ 22 i = 1234; 23 } 24 }
對於以上這段代碼,date爲局部變量,i,d,m,y都是形參爲局部變量,day,month,year爲成員變量。下面分析一下代碼執行時候的變化:
1. main方法開始執行:int date = 9;
date局部變量,基礎類型,引用和值都存在棧中。
2. Test test = new Test();
test爲對象引用,存在棧中,對象(new Test())存在堆中。
3. test.change(date);
i爲局部變量,引用和值存在棧中。當方法change執行完成後,i就會從棧中消失。
4. BirthDate d1= new BirthDate(7,7,1970);
d1爲對象引用,存在棧中,對象(new BirthDate())存在堆中,其中d,m,y爲局部變量存儲在棧中,且它們的類型爲基礎類型,所以它們的數據也存儲在棧中。day,month,year爲成員變量,它們存儲在堆中(new BirthDate()裏面)。當BirthDate構造方法執行完以後,d,m,y將從棧中消失。
5.main方法執行完以後,date變量,test,d1引用將從棧中消失,new Test(),new BirthDate()將等待垃圾回收。
參考:<http://www.iteye.com/topic/634530>
<http://www.cnblogs.com/xiohao/p/4296088.html>
《深刻理解java虛擬機———jvm高級特性與最佳實踐》
JAVA -Xms -Xmx -XX:PermSize -XX:MaxPermSize 區別
JVM按照其存儲數據的內容將所需內存分配爲堆區與非堆區兩個部分:所謂堆區即爲經過new的方式建立的對象(類實例)所佔用的內存空間;非堆區即爲代碼、常量、外部訪問(如文件訪問流所佔資源)等。
常見參數種類(配置內存):(-Xms 、-Xmx、-XX:newSize、-XX:MaxnewSize、-Xmn)、(-XX:PermSize、-XX:MaxPermSize)。能夠從列舉的方式上看出個人用意,參數的配置是分組的,前者是用來配置堆區的,後者是用來配置非堆區的。
第一組配置參數:-Xms 、-Xmx、-XX:newSize、-XX:MaxnewSize、-Xmn
一、-Xms :表示java虛擬機堆區內存初始內存分配的大小,一般爲操做系統可用內存的1/64大小便可,但仍需按照實際狀況進行分配。有可能真的按照這樣的一個規則分配時,設計出的軟件尚未可以運行得起來就掛了。
二、-Xmx: 表示java虛擬機堆區內存可被分配的最大上限,一般爲操做系統可用內存的1/4大小。可是開發過程當中,一般會將 -Xms 與 -Xmx兩個參數的配置相同的值,其目的是爲了可以在java垃圾回收機制清理完堆區後不須要從新分隔計算堆區的大小而浪費資源。
接下來要講述的三個參數是用來控制新生代內存大小的。
一、-XX:newSize:表示新生代初始內存的大小,應該小於 -Xms的值;
二、-XX:MaxnewSize:表示新生代可被分配的內存的最大上限;固然這個值應該小於 -Xmx的值;
三、-Xmn:至於這個參數則是對 -XX:newSize、-XX:MaxnewSize兩個參數的同時配置,也就是說若是經過-Xmn來配置新生代的內存大小,那麼-XX:newSize = -XX:MaxnewSize = -Xmn,雖然會很方便,但須要注意的是這個參數是在JDK1.4版本之後才使用的。
上面所述即爲java虛擬機對外提供的可配置堆區的參數,接下來說述java虛擬機對非堆區內存配置的兩個參數:
一、-XX:PermSize:表示非堆區初始內存分配大小,其縮寫爲permanent size(持久化內存)
二、-XX:MaxPermSize:表示對非堆區分配的內存的最大上限。