《深入理解Java虚拟机》读书笔记一
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                《深入理解Java虚拟机》读书笔记一
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                第二章 Java內存區域與內存溢出異常
1、運行時數據區域
程序計數器:
- 當前線程所執行的字節碼的行號指示器,用于存放下一條需要運行的指令。
- 運行速度最快位于處理器內部。
- 線程私有。
虛擬機棧:
- 描述的是Java方法執行的內存模型,用于存放對象的引用和基本數據類型。
- 每個方法執行的時候都會創建一個棧幀(stack frame)用于存放 局部變量表、操作棧、動態鏈接、方法出口。
- 線程私有,生命周期與線程相同。
方法棧:
- 和虛擬機棧功能類似,管理本地的方法調用。
- 虛擬機棧為虛擬機執行的Java方法的方法服務,方法棧則為虛擬機使用的本地方法的服務。
堆:
- 虛擬機最大的一塊區域,虛擬機啟動的時候創建。
- 用于存放對象的實例,所有對象實例和數據的在堆上分配內存。
- 線程共享的區域。
方法區:
- 用于存放一些類信息,常量,靜態變量和即時編譯后的代碼等數據。
- 線程共享的區域。
運行時常量池:
- 方法區的一部分,用于存放編譯期生成的各種字面量和符號引用。
直接內存:
- 不屬于運行時數據區,堆外內存。
2、HotSpot虛擬機對象探秘
對象的創建:
- 接受new關鍵字指令后,檢查指令參數是否能在常量池中定位到一個類的符號引用
- 然后檢查符號引用對應的類是否已被加載、解析和初始化。如果沒有就執行。
- 類加載通過后,虛擬機為新生的對象分配內存。
- 內存分配完成后,虛擬機需要將分配到的內存空間都初始化為零值。
- 虛擬機設置對象頭信息。
內存分配的方式:
- 指正碰撞,內存是規整的,所有用過的內存放在一邊,空閑的內存放在另一邊,中間放著一個指針作為分界點的指示器。
- 空閑列表,內存不規整,虛擬機維護一個列表用來記錄那些內存是可用的,分配時從中找到足夠的內存劃分給對象,并更新表記錄。
保證線程安全的方式:
- CAS,對分配的內存空間進行同步處理,采用CAS配上失敗重試的方式保證操作的原子性。
- 線程分配緩沖區,把內存分配的動作按照線程劃分在不同的空間之中進行,即每個線程在Java堆中預先分配好內存。
對象的內存布局:
- 對象在內存中存儲的布局可以分為三塊區域對象頭、實例數據和對齊填充。
- 對象頭,又可以分為兩部分,第一部分存儲自身運行時數據,第二部分是類型指針
- 自身運行數據主要包括哈希碼、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID、偏向時間戳。
- 類型指針即對象指向他的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。
- 實例數據,對象真正存儲的有用的有效信息,繼承父類的字段也會包含。
- 對齊填充,對象起始地址必須是8的整數倍,對齊填充起到了占位符的作用。
對象的訪問定位:
- 使用句柄的訪問方式,堆中將劃分出來一塊內存作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址。reference中存儲的是穩定的句柄地址,如果對象被移動,reference的地址無需改變。
- 使用直接指針訪問,reference中存儲的直接就是對象的地址。直接指針訪問可以減少指針定位的時間開銷。
3、OOM異常
- Java堆溢出,Java堆用于存儲對象實例,只要不斷的創建對象,并且保證GC Root到對象之間有可達路徑來避免垃圾回收,那么對象數量到達最大堆的容量限制后就會產生內存溢出異常。  package com.ecut.exception;import java.util.ArrayList;
import java.util.List;/*** -Xms20m -Xmx20m  -XX:+HeapDumpOnOutOfMemoryError*/
public class HeapOOM {static class OOMObject{}public static void main(String[] args) {List<OOMObject> list = new ArrayList<>();while (true){list.add(new OOMObject());}}
}  運行結果如下: java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid6776.hprof ... Heap dump file created [28247587 bytes in 0.149 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3210)at java.util.Arrays.copyOf(Arrays.java:3181)at java.util.ArrayList.grow(ArrayList.java:261)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)at java.util.ArrayList.add(ArrayList.java:458)at com.ecut.exception.HeapOOM.main(HeapOOM.java:17)
- 虛擬機棧和本地方法棧溢出,如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError異常,如果虛擬機在拓展棧時無法申請到足夠的內存空間則拋出OutOfMemoryError異常。  package com.ecut.exception;/*** -Xss128k*/
public class JavaVMStackSOF {private int stackLength = 1;public void stackLeak(){stackLength++;stackLeak();}public static void main(String[] args) {JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();try {javaVMStackSOF.stackLeak();}catch (Exception e){System.out.println("stack length :" + javaVMStackSOF.stackLength);throw e;}}
}  運行結果如下: Exception in thread "main" java.lang.StackOverflowErrorat com.ecut.exception.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)創建線程導致內存溢出異常: package com.ecut.exception;/*** -Xss2M*/ public class JavaVMStackOOM {private void dontStop(){while(true){}}public void stackLeakByThread(){while (true){Thread thread = new Thread(new Runnable() {@Overridepublic void run() {dontStop();}});thread.start();}}public static void main(String[] args) {JavaVMStackOOM javaVMStackOOM = new JavaVMStackOOM();javaVMStackOOM.stackLeakByThread();} }
- 方法區和運行時常量池溢出  package com.ecut.exception;import java.util.ArrayList;
import java.util.List;/*** -XX:PermSize=10M -XX:MaxPermSize=10M  JDK 1.6 會拋出OOM異常,JDK1.7開始了去永久代*/
public class RuntimeConstantPoolOOM {public static void main(String[] args) {//使用list保持著產量池的引用,避免fullGC回收常量池的行為List<String> list  = new ArrayList<>();int i = 0 ;while(true){list.add(String.valueOf(i++));}}
}  String.intern()方法如果字符串常量池中已經包含了一個等于String對象的字符串,則返回代表池中這個字符串的String對象。否則將此對象包含的字符串添加到常量池中。 package com.ecut.exception;public class RuntimeConstantPool {public static void main(String[] args) {/*jdk1.6 intern方法會把首次遇到的字符串實例復制到永久代中,返回的也是這個永久代中的這個字符串實例的引用。StringBuilder創建的字符串實例在Java堆上,所以必然不是同一個引用jdk1.7中intern實現只是在常量池中記錄首次出現的實例引用,因此intern返回的引用和StringBuilder創建的那個字符串實例時同一個*/String s1 = new StringBuilder("計算機").append("軟件").toString();System.out.println(s1.intern() == s1);} }運行結果: true
- 本機直接內存溢出  package com.ecut.exception;import sun.misc.Unsafe;import java.lang.reflect.Field;/***  -Xmx20M -XX:MaxDirectMemorySize = 10M*/
public class DirectMemoryOOM {private  static final int _1MB = 1024*1024;public static void main(String[] args) throws IllegalAccessException {Field unsafeField = Unsafe.class.getDeclaredFields()[0];unsafeField.setAccessible(true);Unsafe unsafe = (Unsafe) unsafeField.get(null);while (true){unsafe.allocateMemory(_1MB);}}
}  運行結果如下: Exception in thread "main" java.lang.OutOfMemoryErrorat sun.misc.Unsafe.allocateMemory(Native Method)at com.ecut.exception.DirectMemoryOOM.main(DirectMemoryOOM.java:18)
源碼地址:
https://github.com/SaberZheng/jvm-test
轉載請于明顯處標明出處:
https://www.cnblogs.com/AmyZheng/p/10504443.html
轉載于:https://www.cnblogs.com/AmyZheng/p/10504443.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的《深入理解Java虚拟机》读书笔记一的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 用户模式 内核模式 linux,linu
- 下一篇: ug安装教程详细步骤ug怎么免费安装教程
