日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

《深入理解Java虚拟机》读书笔记一

發(fā)布時間:2023/12/10 java 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《深入理解Java虚拟机》读书笔记一 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

第二章 Java內(nèi)存區(qū)域與內(nèi)存溢出異常

1、運行時數(shù)據(jù)區(qū)域

程序計數(shù)器:

  • 當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器,用于存放下一條需要運行的指令。
  • 運行速度最快位于處理器內(nèi)部。
  • 線程私有。

虛擬機(jī)棧:

  • 描述的是Java方法執(zhí)行的內(nèi)存模型,用于存放對象的引用和基本數(shù)據(jù)類型。
  • 每個方法執(zhí)行的時候都會創(chuàng)建一個棧幀(stack frame)用于存放 局部變量表、操作棧、動態(tài)鏈接、方法出口。
  • 線程私有,生命周期與線程相同。

方法棧:

  • 和虛擬機(jī)棧功能類似,管理本地的方法調(diào)用。
  • 虛擬機(jī)棧為虛擬機(jī)執(zhí)行的Java方法的方法服務(wù),方法棧則為虛擬機(jī)使用的本地方法的服務(wù)。

堆:

  • 虛擬機(jī)最大的一塊區(qū)域,虛擬機(jī)啟動的時候創(chuàng)建。
  • 用于存放對象的實例,所有對象實例和數(shù)據(jù)的在堆上分配內(nèi)存。
  • 線程共享的區(qū)域。

方法區(qū):

  • 用于存放一些類信息,常量,靜態(tài)變量和即時編譯后的代碼等數(shù)據(jù)。
  • 線程共享的區(qū)域。

運行時常量池:

  • 方法區(qū)的一部分,用于存放編譯期生成的各種字面量和符號引用。

直接內(nèi)存:

  • 不屬于運行時數(shù)據(jù)區(qū),堆外內(nèi)存。

2、HotSpot虛擬機(jī)對象探秘

對象的創(chuàng)建:

  • 接受new關(guān)鍵字指令后,檢查指令參數(shù)是否能在常量池中定位到一個類的符號引用
  • 然后檢查符號引用對應(yīng)的類是否已被加載、解析和初始化。如果沒有就執(zhí)行。
  • 類加載通過后,虛擬機(jī)為新生的對象分配內(nèi)存。
  • 內(nèi)存分配完成后,虛擬機(jī)需要將分配到的內(nèi)存空間都初始化為零值。
  • 虛擬機(jī)設(shè)置對象頭信息。

內(nèi)存分配的方式:

  • 指正碰撞,內(nèi)存是規(guī)整的,所有用過的內(nèi)存放在一邊,空閑的內(nèi)存放在另一邊,中間放著一個指針作為分界點的指示器。
  • 空閑列表,內(nèi)存不規(guī)整,虛擬機(jī)維護(hù)一個列表用來記錄那些內(nèi)存是可用的,分配時從中找到足夠的內(nèi)存劃分給對象,并更新表記錄。

保證線程安全的方式:

  • CAS,對分配的內(nèi)存空間進(jìn)行同步處理,采用CAS配上失敗重試的方式保證操作的原子性。
  • 線程分配緩沖區(qū),把內(nèi)存分配的動作按照線程劃分在不同的空間之中進(jìn)行,即每個線程在Java堆中預(yù)先分配好內(nèi)存。

對象的內(nèi)存布局:

  • 對象在內(nèi)存中存儲的布局可以分為三塊區(qū)域?qū)ο箢^、實例數(shù)據(jù)和對齊填充。
  • 對象頭,又可以分為兩部分,第一部分存儲自身運行時數(shù)據(jù),第二部分是類型指針
  • 自身運行數(shù)據(jù)主要包括哈希碼、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時間戳。
  • 類型指針即對象指向他的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個指針來確定這個對象是哪個類的實例。
  • 實例數(shù)據(jù),對象真正存儲的有用的有效信息,繼承父類的字段也會包含。
  • 對齊填充,對象起始地址必須是8的整數(shù)倍,對齊填充起到了占位符的作用。

對象的訪問定位:

  • 使用句柄的訪問方式,堆中將劃分出來一塊內(nèi)存作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址。reference中存儲的是穩(wěn)定的句柄地址,如果對象被移動,reference的地址無需改變。
  • 使用直接指針訪問,reference中存儲的直接就是對象的地址。直接指針訪問可以減少指針定位的時間開銷。

3、OOM異常

  • Java堆溢出,Java堆用于存儲對象實例,只要不斷的創(chuàng)建對象,并且保證GC Root到對象之間有可達(dá)路徑來避免垃圾回收,那么對象數(shù)量到達(dá)最大堆的容量限制后就會產(chǎn)生內(nèi)存溢出異常。 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());}} }

    運行結(jié)果如下:

    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)
  • 虛擬機(jī)棧和本地方法棧溢出,如果線程請求的棧深度大于虛擬機(jī)所允許的最大深度,將拋出StackOverflowError異常,如果虛擬機(jī)在拓展棧時無法申請到足夠的內(nèi)存空間則拋出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;}} }

    運行結(jié)果如下:

    Exception in thread "main" java.lang.StackOverflowErrorat com.ecut.exception.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)

    創(chuàng)建線程導(dǎo)致內(nèi)存溢出異常:

    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();} }
  • 方法區(qū)和運行時常量池溢出 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保持著產(chǎn)量池的引用,避免fullGC回收常量池的行為List<String> list = new ArrayList<>();int i = 0 ;while(true){list.add(String.valueOf(i++));}} }

    String.intern()方法如果字符串常量池中已經(jīng)包含了一個等于String對象的字符串,則返回代表池中這個字符串的String對象。否則將此對象包含的字符串添加到常量池中。

    package com.ecut.exception;public class RuntimeConstantPool {public static void main(String[] args) {/*jdk1.6 intern方法會把首次遇到的字符串實例復(fù)制到永久代中,返回的也是這個永久代中的這個字符串實例的引用。StringBuilder創(chuàng)建的字符串實例在Java堆上,所以必然不是同一個引用jdk1.7中intern實現(xiàn)只是在常量池中記錄首次出現(xiàn)的實例引用,因此intern返回的引用和StringBuilder創(chuàng)建的那個字符串實例時同一個*/String s1 = new StringBuilder("計算機(jī)").append("軟件").toString();System.out.println(s1.intern() == s1);} }

    運行結(jié)果:

    true
  • 本機(jī)直接內(nèi)存溢出 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);}} }

    運行結(jié)果如下:

    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

轉(zhuǎn)載請于明顯處標(biāo)明出處:

https://www.cnblogs.com/AmyZheng/p/10504443.html

轉(zhuǎn)載于:https://www.cnblogs.com/AmyZheng/p/10504443.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的《深入理解Java虚拟机》读书笔记一的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。