網站首頁 編程語言 正文
目錄
1. Tomcat類加載器機制
2. jdk體系結構與跨平臺特性
?3. JVM內存結構
3.1 jvm內存指令手冊
?3.2 使用jvisualvm工具查看對象回收
4. jvm常用參數設置
4.1 模擬桟溢出實戰
1. Tomcat類加載器機制
tomcat為什么可以多個war包共存,tomcat每有一個war包都會加載一個war包的類加載器,這個類加載器叫webappclassLoader。每個jsp都會使用自己的類加載器加載,所以不需要編譯就可以生效。
?
?
2. jdk體系結構與跨平臺特性
?jdk體系結構:
jdk:java開發工具包含jre和jvm,比如我們常用的java,javac,javap,jar命令
jre:java運行時環境,包含了我們運行java環境的一些常用核心類庫。
jvm:java虛擬機,java類文件運行都依賴于java虛擬機。
?
?3. JVM內存結構
jvm內存結構大體如下:
1.類加載子系統
2.java運行時環境(*重要)
3.字節碼執行引擎
每個線程獨有的:桟,本地方法桟,程序計數器
? ? ? ? 桟:存放每塊方法獨有的桟幀
? ? ? ? 本地方法桟:調用native方法時需要劃分內存
? ? ? ? 程序計數器:每次做操作,字節碼執行引擎都會對程序計數器進行修改。
共享的:堆,方法區。
????????方法區:靜態變量,常量,類信息
? ? ? ? 堆:年輕代-1/3(eden(8/10),s0(1/10),s1(1/10))+老年代-2/3
STW:stop the world,為了回收垃圾對象停止整個虛擬機,會讓web應用出現卡頓的情況。
Mimor GC:
????????eden->s0:對象創建在eden,eden內存占滿,執行引擎調用GC進程執行mimorGC,清空eden,復制存活對象到S0區,對象分代年齡+1
? ? ? ? eden->s0->s1:eden內存占滿,執行引擎調用GC進程執行mimorGC,清空eden和s0,復制存活對象到S1區,對象分代年齡+1
? ? ? ? eden->s1->s0:eden內存占滿,執行引擎調用GC進程執行mimorGC,清空eden和s1,復制存活對象到S0區,對象分代年齡+1
? ? ? ? 上述步驟執行15次以后會進入老年代,也有可能復制到S0或者S1復制不下直接放入老年代的情況。
Full GC:回收方法區和堆區,如果堆區無法回收對象仍然被GC ROOT引用,這時仍然有對象創建,就會報OOM錯誤。主要對JVM優化就是為了優化這個GC
GC ROOT:程序方法桟中的局部變量,方法區中的常量和靜態變量都適合作為一個GCroot。
桟結構如下:?
每個方法都會在桟中分配一塊內存空間,這個內存空間叫桟幀。桟結構,遵循后進先出結構
桟幀分為:局部變量,操作數棧,動態鏈接,方法出口幾個概念。我們需要使用javap -v class文件 > 1.txt中間中查看。
?
?
/**
* javap -c Math.class生成文件如下
* 可以通過閱讀jvm指令手冊查看運行過程
* Compiled from "Math.java"
* public class suanshu.Math {
* public suanshu.Math();
* Code:
* 0: aload_0
* 1: invokespecial #1 // Method java/lang/Object."":()V
* 4: return
*
* public static void compute();
* Code:
* 0: iconst_1
* 1: istore_0
* 2: iconst_2
* 3: istore_1
* 4: iload_0
* 5: iload_1
* 6: iadd
* 7: bipush 10
* 9: imul
* 10: istore_2
* 11: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
* 14: iload_2
* 15: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
* 18: return
*
* public static void main(java.lang.String[]);
* Code:
* 0: invokestatic #4 // Method compute:()V
* 3: return
* }
*/
public class Math {
public static void compute(){
int a = 1;
int b = 2;
int c = (a+b) * 10;
System.out.println(c);
}
public static void main(String[] args) {
Math.compute();
}
}
3.1 jvm內存指令手冊
棧和局部變量操作將常量壓入棧的指令aconst_null 將null對象引用壓入棧iconst_m1 將int類型常量-1壓入棧iconst_0 將int類型常量0壓入棧iconst_1 將int類型常量1壓入 操作數棧iconst_2 將int類型常量2壓入棧iconst_3 將int類型常量3壓入棧iconst_4 將int類型常量4壓入棧iconst_5 將int類型常量5壓入棧lconst_0 將long類型常量0壓入棧lconst_1 將long類型常量1壓入棧fconst_0 將float類型常量0壓入棧fconst_1 將float類型常量1壓入棧dconst_0 將double類型常量0壓入棧dconst_1 將double類型常量1壓入棧bipush 將一個8位帶符號整數壓入棧sipush 將16位帶符號整數壓入棧ldc 把常量池中的項壓入棧ldc_w 把常量池中的項壓入棧(使用寬索引)ldc2_w 把常量池中long類型或者double類型的項壓入棧(使用寬索引)從棧中的局部變量中裝載值的指令iload 從局部變量中裝載int類型值lload 從局部變量中裝載long類型值fload 從局部變量中裝載float類型值dload 從局部變量中裝載double類型值aload 從局部變量中裝載引用類型值(refernce)iload_0 從局部變量0中裝載int類型值iload_1 從局部變量1中裝載int類型值iload_2 從局部變量2中裝載int類型值iload_3 從局部變量3中裝載int類型值lload_0 從局部變量0中裝載long類型值lload_1 從局部變量1中裝載long類型值lload_2 從局部變量2中裝載long類型值lload_3 從局部變量3中裝載long類型值fload_0 從局部變量0中裝載float類型值fload_1 從局部變量1中裝載float類型值 fload_2 從局部變量2中裝載float類型值fload_3 從局部變量3中裝載float類型值dload_0 從局部變量0中裝載double類型值dload_1 從局部變量1中裝載double類型值dload_2 從局部變量2中裝載double類型值dload_3 從局部變量3中裝載double類型值aload_0 從局部變量0中裝載引用類型值aload_1 從局部變量1中裝載引用類型值aload_2 從局部變量2中裝載引用類型值aload_3 從局部變量3中裝載引用類型值iaload 從數組中裝載int類型值laload 從數組中裝載long類型值faload 從數組中裝載float類型值daload 從數組中裝載double類型值aaload 從數組中裝載引用類型值baload 從數組中裝載byte類型或boolean類型值caload 從數組中裝載char類型值saload 從數組中裝載short類型值將棧中的值存入局部變量的指令istore 將int類型值存入局部變量lstore 將long類型值存入局部變量fstore 將float類型值存入局部變量dstore 將double類型值存入局部變量astore 將將引用類型或returnAddress類型值存入局部變量istore_0 將int類型值存入局部變量0istore_1 將int類型值存入局部變量1istore_2 將int類型值存入局部變量2istore_3 將int類型值存入局部變量3lstore_0 將long類型值存入局部變量0lstore_1 將long類型值存入局部變量1lstore_2 將long類型值存入局部變量2lstore_3 將long類型值存入局部變量3fstore_0 將float類型值存入局部變量0fstore_1 將float類型值存入局部變量1fstore_2 將float類型值存入局部變量2fstore_3 將float類型值存入局部變量3dstore_0 將double類型值存入局部變量0dstore_1 將double類型值存入局部變量1 dstore_2 將double類型值存入局部變量2dstore_3 將double類型值存入局部變量3astore_0 將引用類型或returnAddress類型值存入局部變量0astore_1 將引用類型或returnAddress類型值存入局部變量1astore_2 將引用類型或returnAddress類型值存入局部變量2astore_3 將引用類型或returnAddress類型值存入局部變量3iastore 將int類型值存入數組中lastore 將long類型值存入數組中fastore 將float類型值存入數組中dastore 將double類型值存入數組中aastore 將引用類型值存入數組中bastore 將byte類型或者boolean類型值存入數組中castore 將char類型值存入數組中sastore 將short類型值存入數組中wide指令wide 使用附加字節擴展局部變量索引通用(無類型)棧操作nop 不做任何操作pop 彈出棧頂端一個字長的內容pop2 彈出棧頂端兩個字長的內容dup 復制棧頂部一個字長內容dup_x1 復制棧頂部一個字長的內容,然后將復制內容及原來彈出的兩個字長的內容壓入棧dup_x2 復制棧頂部一個字長的內容,然后將復制內容及原來彈出的三個字長的內容壓入棧dup2 復制棧頂部兩個字長內容dup2_x1 復制棧頂部兩個字長的內容,然后將復制內容及原來彈出的三個字長的內容壓入棧dup2_x2 復制棧頂部兩個字長的內容,然后將復制內容及原來彈出的四個字長的內容壓入棧swap 交換棧頂部兩個字長內容類型轉換i2l 把int類型的數據轉化為long類型i2f 把int類型的數據轉化為float類型i2d 把int類型的數據轉化為double類型l2i 把long類型的數據轉化為int類型l2f 把long類型的數據轉化為float類型l2d 把long類型的數據轉化為double類型 f2i 把float類型的數據轉化為int類型f2l 把float類型的數據轉化為long類型f2d 把float類型的數據轉化為double類型d2i 把double類型的數據轉化為int類型d2l 把double類型的數據轉化為long類型d2f 把double類型的數據轉化為float類型i2b 把int類型的數據轉化為byte類型i2c 把int類型的數據轉化為char類型i2s 把int類型的數據轉化為short類型整數運算iadd 執行int類型的加法ladd 執行long類型的加法isub 執行int類型的減法lsub 執行long類型的減法imul 執行int類型的乘法lmul 執行long類型的乘法idiv 執行int類型的除法ldiv 執行long類型的除法irem 計算int類型除法的余數lrem 計算long類型除法的余數ineg 對一個int類型值進行取反操作lneg 對一個long類型值進行取反操作iinc 把一個常量值加到一個int類型的局部變量上邏輯運算移位操作ishl 執行int類型的向左移位操作lshl 執行long類型的向左移位操作ishr 執行int類型的向右移位操作lshr 執行long類型的向右移位操作iushr 執行int類型的向右邏輯移位操作lushr 執行long類型的向右邏輯移位操作按位布爾運算iand 對int類型值進行“邏輯與”操作land 對long類型值進行“邏輯與”操作ior 對int類型值進行“邏輯或”操作lor 對long類型值進行“邏輯或”操作ixor 對int類型值進行“邏輯異或”操作lxor 對long類型值進行“邏輯異或”操作 浮點運算fadd 執行float類型的加法dadd 執行double類型的加法fsub 執行float類型的減法dsub 執行double類型的減法fmul 執行float類型的乘法dmul 執行double類型的乘法fdiv 執行float類型的除法ddiv 執行double類型的除法frem 計算float類型除法的余數drem 計算double類型除法的余數fneg 將一個float類型的數值取反dneg 將一個double類型的數值取反對象和數組對象操作指令new 創建一個新對象checkcast 確定對象為所給定的類型getfield 從對象中獲取字段putfield 設置對象中字段的值getstatic 從類中獲取靜態字段putstatic 設置類中靜態字段的值instanceof 判斷對象是否為給定的類型數組操作指令newarray 分配數據成員類型為基本上數據類型的新數組anewarray 分配數據成員類型為引用類型的新數組arraylength 獲取數組長度multianewarray 分配新的多維數組控制流條件分支指令ifeq 如果等于0,則跳轉ifne 如果不等于0,則跳轉iflt 如果小于0,則跳轉ifge 如果大于等于0,則跳轉ifgt 如果大于0,則跳轉ifle 如果小于等于0,則跳轉if_icmpcq 如果兩個int值相等,則跳轉if_icmpne 如果兩個int類型值不相等,則跳轉if_icmplt 如果一個int類型值小于另外一個int類型值,則跳轉 if_icmpge 如果一個int類型值大于或者等于另外一個int類型值,則跳轉if_icmpgt 如果一個int類型值大于另外一個int類型值,則跳轉if_icmple 如果一個int類型值小于或者等于另外一個int類型值,則跳轉ifnull 如果等于null,則跳轉ifnonnull 如果不等于null,則跳轉if_acmpeq 如果兩個對象引用相等,則跳轉if_acmpnc 如果兩個對象引用不相等,則跳轉比較指令lcmp 比較long類型值fcmpl 比較float類型值(當遇到NaN時,返回-1)fcmpg 比較float類型值(當遇到NaN時,返回1)dcmpl 比較double類型值(當遇到NaN時,返回-1)dcmpg 比較double類型值(當遇到NaN時,返回1)無條件轉移指令goto 無條件跳轉goto_w 無條件跳轉(寬索引)表跳轉指令tableswitch 通過索引訪問跳轉表,并跳轉lookupswitch 通過鍵值匹配訪問跳轉表,并執行跳轉操作異常athrow 拋出異常或錯誤finally子句jsr 跳轉到子例程jsr_w 跳轉到子例程(寬索引)rct 從子例程返回方法調用與返回方法調用指令invokcvirtual 運行時按照對象的類來調用實例方法invokespecial 根據編譯時類型來調用實例方法invokestatic 調用類(靜態)方法invokcinterface 調用接口方法方法返回指令ireturn 從方法中返回int類型的數據lreturn 從方法中返回long類型的數據freturn 從方法中返回float類型的數據dreturn 從方法中返回double類型的數據areturn 從方法中返回引用類型的數據return 從方法中返回,返回值為void 線程同步montiorenter 進入并獲取對象監視器monitorexit 釋放并退出對象監視器JVM指令助記符變量到操作數棧:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_操作數棧到變量:istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_常數到操作數棧:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,fconst_,dconst_加:iadd,ladd,fadd,dadd減:isub,lsub,fsub,dsub乘:imul,lmul,fmul,dmul除:idiv,ldiv,fdiv,ddiv余數:irem,lrem,frem,drem取負:ineg,lneg,fneg,dneg移位:ishl,lshr,iushr,lshl,lshr,lushr按位或:ior,lor按位與:iand,land按位異或:ixor,lxor類型轉換:i2l,i2f,i2d,l2f,l2d,f2d(放寬數值轉換)i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f(縮窄數值轉換)創建類實便:new創建新數組:newarray,anewarray,multianwarray訪問類的域和類實例域:getfield,putfield,getstatic,putstatic把數據裝載到操作數棧:baload,caload,saload,iaload,laload,faload,daload,aaload從操作數棧存存儲到數組:bastore,castore,sastore,iastore,lastore,fastore,dastore,aastore獲取數組長度:arraylength檢相類實例或數組屬性:instanceof,checkcast操作數棧管理:pop,pop2,dup,dup2,dup_xl,dup2_xl,dup_x2,dup2_x2,swap有條件轉移:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonnull,if_icmpeq,if_icmpene,if_icmplt,if_icmpgt,if_icmple,if_icmpge,if_acmpeq,if_acmpne,lcmp,fcmplfcmpg,dcmpl,dcmpg復合條件轉移:tableswitch,lookupswitch無條件轉移:goto,goto_w,jsr,jsr_w,ret調度對象的實便方法:invokevirtual調用由接口實現的方法:invokeinterface調用需要特殊處理的實例方法:invokespecial 調用命名類中的靜態方法:invokestatic方法返回:ireturn,lreturn,freturn,dreturn,areturn,return異常:athrowfinally關鍵字的實現使用:jsr,jsr_w,ret
?3.2 使用jvisualvm工具查看對象回收
在cmd窗口中輸入jvisualvm,寫一個死循環代碼查看內存回收情況。
?
import java.util.ArrayList;
public class Math {
public static void main(String[] args) throws InterruptedException {
ArrayList
4. jvm常用參數設置
常用參數設置:java -Xms2048m -xmx2048m -xmn1024m -xss512k -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar jar包
方法區的元空間設置:默認21M,如果達到21M以后會進行Full GC,回收堆和方法區,如果回收后的內存房間很小,下次的方法區內存會變小,如果內存無法回收會進行擴容,這個機制叫動態擴容機制。所以一般我們都設置一下默認大小和最大大小。防止元空間把內存條撐爆。
-Xss:桟中線程內存大小,因為元空間和桟都是用的直接內存,如果值設置的越大,有可能線程使用的內存越大,內存總有用完的一天會導致無法開啟更多線程,默認1M,如果設置越小,反而可以開啟更多線程。
?
4.1 模擬桟溢出實戰
?寫一個遞歸調用,讓桟中不停往下壓方法創建內存,把桟撐爆。
/**
* 默認1M
*/
public class StackOverFlowTest {
static int count = 0;
public static void compute(){
count ++;
compute();
}
public static void main(String[] args) {
try{
compute();
}catch (Throwable e){
e.printStackTrace();
System.out.println("調用次數:"+count);
}
}
}
?
原文鏈接:https://blog.csdn.net/qq_21575929/article/details/124157258
相關推薦
- 2023-07-08 keycloak更新token調用updateToken函數無效,解決辦法
- 2022-04-07 C++11生成隨機數(random庫)的使用_C 語言
- 2022-09-11 Shell之免交互的實現_linux shell
- 2022-10-23 使用React組件編寫溫度顯示器_React
- 2022-08-29 Python可視化神器pyecharts繪制雷達圖_python
- 2022-03-17 .NET?6開發TodoList應用引入第三方日志庫_實用技巧
- 2023-07-06 css flex實現div固定在瀏覽器右下角
- 2022-05-13 UnicodeEncodeError: ‘utf-8‘ codec can‘t encode cha
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支