面试准备之内存管理
一、內存管理原理
在java中,有java程序、虛擬機、操作系統三個層次,其中java程序與虛擬機交互,而虛擬機與操作系統間交互!這就保證了java程序的平臺無關性!下面我們從程序運行前,程序運行中、程序運行內存溢出三個階段來說一下內存管理原理!
1、程序運行前:JVM向操作系統請求一定的內存空間,稱為初始內存空間!程序執行過程中所需的內存都是由java虛擬機從這片內存空間中劃分的。 2、程序運行中:java程序一直向java虛擬機申請內存,當程序所需要的內存空間超出初始內存空間時,java虛擬機會再次向操作系統申請更多的內存供程序使用! 3、內存溢出:程序接著運行,當java虛擬機已申請的內存達到了規定的最大內存空間,但程序還需要更多的內存,這時會出現內存溢出的錯誤!至此可以看出,Java 程序所使用的內存是由 Java 虛擬機進行管理、分配的。Java 虛擬機規定了 Java 程序的初始內存空間和最大內存空間,開發者只需要關心 Java 虛擬機是如何管理內存空間的,而不用關心某一種操作系統是如何管理內存的。
?
二、內存空間邏輯劃分
JVM 會把申請的內存從邏輯上劃分為三個區域,即:方法區、堆與棧。?
方法區:方法區默認最大容量為64M,Java虛擬機會將加載的java類存入方法區,保存類的結構(屬性與方法),類靜態成員等內容。? 堆:默認最大容量為64M,堆存放對象持有的數據,同時保持對原類的引用。可以簡單的理解為對象屬性的值保存在堆中,對象調用的方法保存在方法區。 棧(虛擬機棧):棧默認最大容量為1M,在程序運行時,每當遇到方法調用時,Java虛擬機就會在棧中劃分一塊內存稱為棧幀(Stack frame),棧幀中的內存供局部變量(包括基本類型與引用類型)使用,當方法調用結束后,Java虛擬機會收回此棧幀占用的內存。 運行時常量池:是方法區的一部分。用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后存放到方法去的運行時常量池中。 程序計數器是一塊較小的內存空間,它的作用可以看做是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型里(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現),字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。如果線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;如果正在執行的是Natvie方法,這個計數器值則為空(Undefined)。此內存區域是唯一一個在Java虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。
本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的Native方法服務。虛擬機規范中對本地方法棧中的方法使用的語言、使用方式與數據結構并沒有強制規定,因此具體的虛擬機可以自由實現它
?
三、java數據類型 1、基本數據類型:沒封裝指針的變量。 聲明此類型變量,只會在棧中分配一塊內存空間。 2、引用類型:就是底層封裝指針的數據類型。 他們在內存中分配兩塊空間,第一塊內存分配在棧中,只存放別的內存地址,不存放具體數值,我們也把它叫指針類型的變量,第二塊內存分配在堆中,存放的是具體數值,如對象屬性值等。 3、下面我們從一個例子來看一看: public class Student {? String stuId;? String stuName;? int stuAge;? }? public class TestStudent {? public static void main(String[] args) {? Student zhouxingxing = new Student();? String name = new String("旺旺"); ? int a = 10;? char b = 'm';? zhouxingxing.stuId = "9527";? zhouxingxing.stuName = "周星星";? zhouxingxing.stuAge = 25;? }? } (1)類當然是存放在方法區里面的。 (2)Student zhouxingxing = new Student();? 這行代碼就創建了兩塊內存空間,第一個在棧中,名字叫zhouxingxing,它就相當于指針類型的變量,我們看到它并不存放學生的姓名、年齡等具體的數值,而是存放堆中第二塊內存的地址,第二塊才存放具體的數值,如學生的編號、姓名、年齡等信息。 (3)int a = 10;?這是?基本數據類型?變量,具體的值就存放在棧中,并沒有只指針的概念! 四、值傳參和引用傳參 (1)參數根據調用后的效果不同,即是否改變參數的原始數值,又可以分為兩種:按值傳遞的參數與按引用傳遞的參數。 按值傳遞的參數原始數值不改變,按引用傳遞的參數原始數值改變!這是為什么呢?其實相當簡單: 我們知道基本數據類型的變量存放在棧里面,變量名處存放的就是變量的值,那么當基本數據類型的變量作為參數時,傳遞的就是這個值,只是把變量的值傳遞了過去,不管對這個值如何操作,都不會改變變量的原始值。而對引用數據類型的變量來說,變量名處存放的地址,所以引用數據類型的變量作為傳參時,傳遞的實際上是地址,對地址處的內容進行操作,當然會改變變量的值了! 五、內存區域調節參數-Xms:初始堆大小,默認為物理內存的1/64(<1GB);默認(MinHeapFreeRatio參數可以調整)空余堆內存小于40%時,JVM就會增大堆直到-Xmx的最大限制
-Xmx:最大堆大小,默認(MaxHeapFreeRatio參數可以調整)空余堆內存大于70%時,JVM會減少堆直到 -Xms的最小限制
-Xmn:新生代的內存空間大小,注意:此處的大小是(eden+ 2 survivor space)。與jmap -heap中顯示的New gen是不同的。整個堆大小=新生代大小 + 老生代大小 + 永久代大小。?
在保證堆大小不變的情況下,增大新生代后,將會減小老生代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。
-XX:SurvivorRatio:新生代中Eden區域與Survivor區域的容量比值,默認值為8。兩個Survivor區與一個Eden區的比值為2:8,一個Survivor區占整個年輕代的1/10。
-Xss:每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。應根據應用的線程所需內存大小進行適當調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。一般小的應用, 如果棧不是很深, 應該是128k夠用的,大的應用建議使用256k。這個選項對性能影響比較大,需要嚴格的測試。和threadstacksize選項解釋很類似,官方文檔似乎沒有解釋,在論壇中有這樣一句話:"-Xss is translated in a VM flag named ThreadStackSize”一般設置這個值就可以了。
-XX:PermSize:設置永久代(perm gen)初始值。默認值為物理內存的1/64。
-XX:MaxPermSize:設置持久代最大值。物理內存的1/4。
?
參考:
http://liu1227787871.blog.163.com/blog/static/205363197201263103320466/
http://www.blogjava.net/chhbjh/archive/2012/01/28/368936.html
http://www.cnblogs.com/gw811/archive/2012/10/18/2730117.html
轉載于:https://www.cnblogs.com/wabi87547568/p/5284110.html
總結
- 上一篇: maven项目部署打包
- 下一篇: 如何在MyEclipse中添加 用户自定