欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java的最大棧深度與JVM核心知識介紹

 更新時間:2021年09月08日 09:27:26   作者:xuxh120  
這篇文章主要有兩個部分,一部分介紹JAVA的最大棧深度,第二部分介紹了JVM核心知識,需要的朋友可以參考下面文章的具體內(nèi)容

一、Java最大支持棧深度有多大?

從Java運行時數(shù)據(jù)區(qū)域我們知道,線程中的 棧結(jié)構(gòu)如下:

每個棧幀包含:本地變量表,操作數(shù)棧,動態(tài)鏈接,返回地址等東西...

也就是說棧調(diào)用深度越大,棧幀就越多,就越耗內(nèi)存。

1、測試案例

1.1、測試線程棧大小對棧深度的影響

下面我們用一個測試例子來說明:

有如下遞歸方法:

public class StackTest {
 
    private int count = 0;
 
    public void recursiveCalls(String a){
        count++;
        System.out.println("stack depth: " + count);
        recursiveCalls(a);
    }
 
    public void test(){
        try {
            recursiveCalls("a");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
 
    public static void main(String[] args) {
        new StackTest().test();
    }
}

我們設(shè)置啟動參數(shù)

-Xms256m -Xmx256m -Xmn128m -Xss256k

輸出內(nèi)容:

stack depth: 1556
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)

可以發(fā)現(xiàn),棧深度為1556的時候,就報 StackOverflowError了。

接下來我們調(diào)整-Xss線程棧大小為 512k,輸出內(nèi)容:

stack depth: 3249
Exception in thread "main" java.lang.StackOverflowError
    at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)

發(fā)現(xiàn)棧深度變味了3249,說明了:

隨著線程棧的大小越大,能夠支持越多的方法調(diào)用,也即是能夠存儲更多的棧幀。

1.2、測試方法參數(shù)個對棧深度的影響

這里我們固定設(shè)置-Xss為256k。

我們知道此時的深度為:1556。

接下來我們給方法添加參數(shù):

public class StackTest {
 
    private int count = 0;
 
    public void recursiveCalls(String a){
        count++;
        System.out.println("stack depth: " + count);
        recursiveCalls(a);
    }
 
    public void test(){
        try {
            recursiveCalls("a");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
 
    public static void main(String[] args) {
        new StackTest().test();
    }
}

為何要添加參數(shù)呢,因為添加參數(shù)之后,棧幀中的本地變量表就會增加內(nèi)容,我們可以嘗試使用以下命令查看下Class文件的匯編指令:

javap -v StackTest.class

可以發(fā)現(xiàn)recursiveCalls方法的本地變量表的確增加了,對應(yīng)方法的入?yún)?a:

LocalVariableTable:
  Start  Length  Slot  Name   Signature
      0      44     0  this   Lcom/itzhai/jvm/stacks/StackTest;
      0      44     1     a   Ljava/lang/String;

這個時候我們在執(zhí)行程序看看結(jié)果:

stack depth: 1318
Exception in thread "main" java.lang.StackOverflowError
    at java.nio.Buffer.<init>(Buffer.java:201)

可以發(fā)現(xiàn),棧深度由原來的1556編程了1318。

可以得出結(jié)論:

局部變量表內(nèi)容越多,那么棧幀就越大,棧深度就越小。

2、結(jié)論

  • 隨著線程棧的大小越大,能夠支持越多的方法調(diào)用,也即是能夠存儲更多的棧幀;局部變量表內(nèi)容越多,那么棧幀就越大,棧深度就越小。
  • 我們在評審寫代碼的時候,發(fā)現(xiàn)了堆棧溢出,可以查看下對應(yīng)類的本地變量表,是不是太多了,可不可以優(yōu)化下代碼,或者加大下線程棧的大小,以增加棧的深度。

二、重溫JVM知識1. JDK,JRE,JVM的聯(lián)系是啥?

  • JVM Java Virtual Machine
  • JDK Java Development Kit
  • JRE Java Runtime Environment

直接上官網(wǎng)上的介紹的圖片,一目了然。

2. JVM的作用是啥?

JVM有2個特別有意思的特性,語言無關(guān)性和平臺無關(guān)性。

  • 語言無關(guān)性:是指實現(xiàn)了Java虛擬機規(guī)范的語言對可以在JVM上運行,如Groovy,和在大數(shù)據(jù)領(lǐng)域比較火的語言Scala,因為JVM最終運行的是class文件,只要最終的class文件復(fù)合規(guī)范就可以在JVM上運行。
  • 平臺無關(guān)性:是指安裝在不同平臺的JVM會把class文件解釋為本地的機器指令,從而實現(xiàn)Write Once,Run Anywhere

3.JVM運行時數(shù)據(jù)區(qū)

Java虛擬機在執(zhí)行Java程序的過程中會把它所管理的內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷毀的時間,有的區(qū)域隨著虛擬機進程的啟動而存在,有些區(qū)域則依賴用戶線程的啟動和結(jié)束而建立和銷毀。

Java虛擬機所管理的內(nèi)存將會包括以下幾個運行時數(shù)據(jù)區(qū)域

其中方法區(qū)和堆是所有線程共享的數(shù)據(jù)區(qū)程序計數(shù)器,虛擬機棧,本地方法棧是線程隔離的數(shù)據(jù)區(qū),畫一個邏輯圖

3.1程序計數(shù)器

程序計數(shù)器是一塊較小的內(nèi)存空間,它可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器

為什么要記錄當(dāng)前線程所執(zhí)行的字節(jié)碼的行號?直接執(zhí)行完不就可以了嗎?

因為代碼是在線程中運行的,線程有可能被掛起。即CPU一會執(zhí)行線程A,線程A還沒有執(zhí)行完被掛起了,接著執(zhí)行線程B,最后又來執(zhí)行線程A了,CPU得知道執(zhí)行線程A的哪一部分指令,線程計數(shù)器會告訴CPU。

3.2虛擬機棧

虛擬機棧存儲當(dāng)前線程運行方法所需要的數(shù)據(jù),指令,返回地址等。

虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀用于存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。每個方法從調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機棧中從入棧道出棧的過程。

局部變量表存儲存儲局部變量,是一個定長為32位的局部變量空間。其中64位長度的long和double類型的數(shù)據(jù)會占用2個局部變量空間(Slot),其余的數(shù)據(jù)類型只占用一個。引用類型(new出來的對象)如何存儲?看下圖

public int methodOne(int a, int b) {
    Object obj = new Object();
    return a + b;}

如果局部變量是Java的8種基本基本數(shù)據(jù)類型,則存在局部變量表中,如果是引用類型。如String,局部變量表中存的是引用,而實例在堆中。

假如methodOne方法調(diào)用methodTwo方法時, 虛擬機棧的情況如下:

當(dāng)虛擬機棧無法再放下棧幀的時候,就會出現(xiàn)StackOverflowError。

接著解釋一下操作數(shù)棧,還是比較容易理解的假如Test.java中有如下方法,

public int getSum(int a, int b) {
    return a + b;
}

反編譯生成的Test.class文件,并輸出到show.txt中

javap -v Test.class > show.txt

show.txt的內(nèi)容如下

public int getSum(int, int);
  descriptor: (II)I
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=3, args_size=3
       0: iload_1
       1: iload_2
       2: iadd
       3: ireturn
    LineNumberTable:
      line 12: 0

解釋一下上面的語句

iload_1:局部變量1壓棧

iload_2:局部變量2壓棧

iadd:棧頂2個元素相加,計算結(jié)果壓棧

簡單2個數(shù)相加都會用到棧,這個棧就是操作數(shù)棧,更不用說復(fù)雜的語法了

3.3本地方法棧

本地方法棧(Native Method Stack)與虛擬機棧鎖發(fā)揮的作用是非常相似的,他們之間的區(qū)別不過是虛擬機棧為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機使用到的Native方法服務(wù)。

3.4Java堆

對于大多數(shù)應(yīng)用來說,Java堆(Java Heap)是Java虛擬機鎖管理的內(nèi)存中最大的一塊。Java堆是所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存。

3.5方法區(qū)

方法區(qū)(Method Area)與Java堆一樣,是各個線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)。

4.JVM內(nèi)存模型

由顏色可以看出,jdk1.8之前,堆內(nèi)存被分為新生代,老年代,永久帶,jdk1.8及以后堆內(nèi)存被分成了新生代和老年代。新生代的區(qū)域又分為eden區(qū),s0區(qū),s1區(qū),默認比例是8:1:1,元空間可以理解為直接的物理內(nèi)存

以上就是Java的最大棧深度與JVM核心知識介紹的詳細內(nèi)容,更多關(guān)于Java最大棧深度與JVM核心知識的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring Data JPA使用Sort進行排序(Using Sort)

    Spring Data JPA使用Sort進行排序(Using Sort)

    本篇文章主要介紹了Spring Data JPA使用Sort進行排序(Using Sort),具有一定的參考價值,有興趣的可以了解一下
    2017-07-07
  • Mybatis中<if>和<choose>的區(qū)別及“=”判斷方式

    Mybatis中<if>和<choose>的區(qū)別及“=”判斷方式

    這篇文章主要介紹了Mybatis中<if>和<choose>的區(qū)別及“=”判斷方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java基礎(chǔ)知識之ByteArrayInputStream流的使用

    Java基礎(chǔ)知識之ByteArrayInputStream流的使用

    這篇文章主要介紹了Java基礎(chǔ)知識之ByteArrayInputStream流的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java實現(xiàn)停車場系統(tǒng)

    java實現(xiàn)停車場系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)停車場系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Spring IoC容器知識點詳解

    Spring IoC容器知識點詳解

    在本篇文章里小編給各位整理的是關(guān)于Spring IoC容器的相關(guān)知識點內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2019-09-09
  • SpringBoot中多環(huán)境啟動配置的教程詳解

    SpringBoot中多環(huán)境啟動配置的教程詳解

    在SpringBoot項目的生命周期中,存在不同的環(huán)境,我們就需要針對不同環(huán)境制定不同名稱的配置文件,里面放置不同環(huán)境下所需的配置項,下面小編就來和大家詳細講講SpringBoot如何進行多環(huán)境啟動配置的吧
    2024-02-02
  • Java前端開發(fā)之HttpServletRequest的使用

    Java前端開發(fā)之HttpServletRequest的使用

    service方法中的request的類型是ServletRequest,而doGet/doPost方法的request的類型是HttpServletRequest,HttpServletRequest是ServletRequest的子接口,功能和方法更加強大
    2023-01-01
  • Java容器類源碼詳解 Deque與ArrayDeque

    Java容器類源碼詳解 Deque與ArrayDeque

    這篇文章主要介紹了Java容器類源碼詳解 Deque與ArrayDeque,Deque 接口繼承自 Queue接口,但 Deque 支持同時從兩端添加或移除元素,因此又被成為雙端隊列。,需要的朋友可以參考下
    2019-06-06
  • Java創(chuàng)建List常用幾種方法

    Java創(chuàng)建List常用幾種方法

    本文主要介紹了Java創(chuàng)建List常用幾種方法,主要介紹了9種方法,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • java異常處理執(zhí)行順序詳解try catch finally

    java異常處理執(zhí)行順序詳解try catch finally

    try catch語句是java語言用于捕獲異常并進行處理的標(biāo)準方式,對于try catch及try catch finally執(zhí)行順序必須有深入的了解
    2021-10-10

最新評論