--Too small initial heap for new size specified


雖然Java屏蔽了一下內存細節,但是有時候,了解一下這些常識還是有好處的,特別是一些面試,總是盯着這些玩意不放手。

 

JVM啟動以后,會分配兩類內存區域,一類用於開發人員使用,比如保存一些變量,對象等,一類JVM自己使用,比如存放一些class類和描述。

 

1,第一類內存區域又可以分為棧(stack)、堆(heap),還有一些靜態存儲區域,這部分的內存在JVM啟動的時候,可以用參數進行配置:

 

-Xms 初始堆大小,這個值不能太小,其初始空間(即-Xms)是物理內存的1/64,這個值不能太小,比如 設置了-Xms1m,運行可能會出現 

Java代碼 復制代碼  收藏代碼
  1. Error occurred during initialization of VM  
  2. Too small initial heap for new size specified  
  Error occurred during initialization of VM
  Too small initial heap for new size specified

 

-Xmx 堆大小上限,最大空間(-Xmx)是物理內存的1/4,如果程序中分配的內存超過了這個限制,那么會出現

Java代碼 復制代碼  收藏代碼
  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

 代碼為:

Java代碼 復制代碼  收藏代碼
  1. byte[] b = new byte[100000000];  
byte[] b = new byte[100000000];

 

 

-Xss  線程棧大小,一般不用設置,JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需內存大小進行調整。有時候會發現一下異常,

Java代碼 復制代碼  收藏代碼
  1. Exception in thread "main" java.lang.StackOverflowError  
Exception in thread "main" java.lang.StackOverflowError

 原因一般是:

Java代碼 復制代碼  收藏代碼
  1. public static int callMyself(){  
  2.     return callMyself();  
  3. }  
	public static int callMyself(){
		return callMyself();
	}

 方法的遞歸或者死循環,導致棧空間不夠用了。

 

 棧和堆到底存些什么,很多地方都有講到,這里參考下《Think in java》的,棧里存放對象引用、基本類型的變量等,而堆里面存放對象和數組。方法的執行是在棧上進行的,這一點可以通過異常的時候,經常會默認打印

Java代碼 復制代碼  收藏代碼
  1. e.printStackTrace();  
e.printStackTrace();

 棧信息得知。

 

Runtime類有幾個函數,我們可以簡單的通過這幾個函數,看看JVM中的一些內存信息。

 

maxMemory()這個方法返回的是java虛擬機(這個進程)能構從操作系統那里挖到的最大的內存,以字節為單位,如果在運行java程序的時  候,沒有添加-Xmx參數,那么就是64兆,也就是說maxMemory()返回的大約是64*1024*1024字節,這是java虛擬機默認情況下能 從操作系統那里挖到的最大的內存。如果添加了-Xmx參數,將以這個參數后面的值為准,例如java -cp ClassPath -Xmx512m  ClassName,那么最大內存就是512*1024*0124字節。

 

totalMemory()這個方法返回的是java虛擬機現在已經從操作系統那里挖過來的內存大小,也就是java虛擬機這個進程當時所占用的所有  內存。如果在運行java的時候沒有添加-Xms參數,那么,在java程序運行的過程的,內存總是慢慢的從操作系統那里挖的,基本上是用多少挖多少,直 挖到maxMemory()為止,所以totalMemory()是慢慢增大的。如果用了-Xms參數,程序在啟動的時候就會無條件的從操作系統中挖-  Xms后面定義的內存數,然后在這些內存用的差不多的時候,再去挖。

 

freeMemory()是什么呢,剛才講到如果在運行java的時候沒有添加-Xms參數,那么,在java程序運行的過程的,內存總是慢慢的從操  作系統那里挖的,基本上是用多少挖多少,但是java虛擬機100%的情況下是會稍微多挖一點的,這些挖過來而又沒有用上的內存,實際上就是  freeMemory(),所以freeMemory()的值一般情況下都是很小的,但是如果你在運行java程序的時候使用了-Xms,這個時候因為程  序在啟動的時候就會無條件的從操作系統中挖-Xms后面定義的內存數,這個時候,挖過來的內存可能大部分沒用上,所以這個時候freeMemory()可 能會有些大。

 

下面我們來看看例子:

Java代碼 復制代碼  收藏代碼
  1. Runtime rt = Runtime.getRuntime();  
  2.   
  3. info("Max   memory: " + rt.maxMemory());  
  4. long fisrt = rt.freeMemory();  
  5. info("Total memory: " + rt.totalMemory());  
  6. info("Free memory: " + fisrt);  
  7.   
  8. int size = 10000;  
  9.   
  10. byte[] b = new byte[size];  
  11. long bL = rt.freeMemory();  
  12. info("Free memory: " + bL);  
  13.    info("byte allocate Cost memory: " + (fisrt - bL) + ", Array size :" + size);  
		Runtime rt = Runtime.getRuntime();
	
		info("Max   memory: " + rt.maxMemory());
		long fisrt = rt.freeMemory();
		info("Total memory: " + rt.totalMemory());
		info("Free memory: " + fisrt);
	
		int size = 10000;
		
		byte[] b = new byte[size];
		long bL = rt.freeMemory();
		info("Free memory: " + bL);
	    info("byte allocate Cost memory: " + (fisrt - bL) + ", Array size :" + size);

 運行參數為 -Xms8m -Xmx32m (太大了可能看不出來),運行結果為:

Java代碼 復制代碼  收藏代碼
  1. 2011-02-22 10:28:01: Max   memory: 33357824  
  2. 2011-02-22 10:28:01: Total memory: 8323072  
  3. 2011-02-22 10:28:01: Free memory: 7791752  
  4. 2011-02-22 10:28:01: Free memory: 7781736  
  5. 2011-02-22 10:28:01: byte allocate Cost memory: 10016, Array size :10000  
2011-02-22 10:28:01: Max   memory: 33357824
2011-02-22 10:28:01: Total memory: 8323072
2011-02-22 10:28:01: Free memory: 7791752
2011-02-22 10:28:01: Free memory: 7781736
2011-02-22 10:28:01: byte allocate Cost memory: 10016, Array size :10000

 33357824 <> 32*1025*1024(大約等於)

 8323072 <> 8×1024×1024

 最后看看10000長度的byte數組,分配了多少內存,大約為10016,這說明除了10000個大小為1字節的byte以外,還有16個字節其他的玩意。

 

將byte換成int(4字節):

 

Java代碼 復制代碼  收藏代碼
  1. 2011-02-22 10:35:21: int allocate Cost memory: 40016, Array size :10000  
2011-02-22 10:35:21: int allocate Cost memory: 40016, Array size :10000

 與byte相同,也是4*10000+16

 

將byte換成long(8字節):

Java代碼 復制代碼  收藏代碼
  1. 2011-02-22 10:32:47: long allocate Cost memory: 80016, Array size :10000  
2011-02-22 10:32:47: long allocate Cost memory: 80016, Array size :10000

與byte相同,也是8*10000+16

 

再看看String數組:

Java代碼 復制代碼  收藏代碼
  1. 2011-02-22 10:34:40: String allocate Cost memory: 40016, Array size :10000  
2011-02-22 10:34:40: String allocate Cost memory: 40016, Array size :10000

 String作為一個對象,分配的內存大小與int相同,說明了這台機器是32(4*8)位的

 

最后看看Object對象,

Java代碼 復制代碼  收藏代碼
  1. 2011-02-22 10:37:02: Object allocate Cost memory: 40016, Array size :10000  
2011-02-22 10:37:02: Object allocate Cost memory: 40016, Array size :10000

 與String一樣。

 

2,第二類內存,我了解的主要是PermGen space,全稱是Permanent Generation  space,是指內存的永久保存區域,這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGen  space中,它和存放類實例(Instance)的Heap區域不同,SUN的JDK在GC(Garbage  Collection)不會在主程序運行期對PermGen space進行清理,所以如果你的應用中有很CLASS的話,就很可能出現PermGen  space錯誤。

    原來SUN  的JVM把內存分了不同的區,其中一個就是permenter區用來存放用得非常多的類和類描述。本來SUN設計的時候認為這個區域在JVM啟動的時候就 固定了,但他沒有想到現在動態會用得這么廣泛。而且這個區域有特殊的垃圾收回機制,現在的問題是動態加載類到這個區域后,gc根本沒辦法回收


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM