国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java內(nèi)存區(qū)域與內(nèi)存溢出

LiuZh / 580人閱讀

摘要:前言最近在讀周志明老師的深入理解虛擬機(jī)感覺一下?lián)Q了一個(gè)角度來(lái)看待代碼,有必要整理一些內(nèi)容,更清楚實(shí)際的流程,這一篇就記錄下內(nèi)存區(qū)域與相關(guān)的一些內(nèi)存溢出的異常。除了這些以外,直接內(nèi)存的不合理分配也會(huì)影響到虛擬機(jī)動(dòng)態(tài)擴(kuò)展內(nèi)存時(shí)出現(xiàn)內(nèi)存溢出。

前言

最近在讀周志明老師的《深入理解Java虛擬機(jī)》,感覺一下?lián)Q了一個(gè)角度來(lái)看待Java代碼,有必要整理一些內(nèi)容,更清楚實(shí)際的流程,這一篇就記錄下Java內(nèi)存區(qū)域與相關(guān)的一些內(nèi)存溢出的異常。

內(nèi)存區(qū)域

Java虛擬機(jī)在執(zhí)行Java程序的過程會(huì)把它管理的內(nèi)存劃分為各個(gè)不同的區(qū)域,這些區(qū)域都有著各自的生命周期,總的來(lái)說(shuō)Java虛擬機(jī)管理的內(nèi)存將會(huì)包括一下的數(shù)據(jù)區(qū)域

圖中可以很清晰的看出區(qū)域里面各個(gè)實(shí)體的關(guān)系,然后簡(jiǎn)單介紹一3下各個(gè)實(shí)體。

1.程序計(jì)數(shù)器

線程私有,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器,字節(jié)碼解釋器的工作就是通過改變計(jì)數(shù)器的值來(lái)進(jìn)行后續(xù)的操作。

2.虛擬機(jī)棧

線程私有,描述的是Java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行的同時(shí)會(huì)創(chuàng)建一個(gè)棧幀用于儲(chǔ)存局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。

3.本地方法棧

與虛擬機(jī)棧發(fā)揮的作用類似,但虛擬機(jī)棧主要是為執(zhí)行Java方法服務(wù),而本地方法棧則為虛擬機(jī)使用到的native方法服務(wù)。

4.Java堆

是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊,也是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,此區(qū)域唯一目的是存放對(duì)象實(shí)例。

5.方法區(qū)

也是各個(gè)線程共享,用于儲(chǔ)存已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù),為堆的一個(gè)邏輯部分。其中的運(yùn)行時(shí)常量池相對(duì)于Class文件常量池而言具備動(dòng)態(tài)性,運(yùn)行期間也可將新的常量放入池中。
除了這些以外,直接內(nèi)存的不合理分配也會(huì)影響到Java虛擬機(jī)動(dòng)態(tài)擴(kuò)展內(nèi)存時(shí)出現(xiàn)內(nèi)存溢出。

從JVM看對(duì)象

Java對(duì)象的創(chuàng)建我們無(wú)時(shí)無(wú)刻都在使用著,這里從虛擬機(jī)層面來(lái)看待對(duì)象的創(chuàng)建。

對(duì)象的創(chuàng)建

1.當(dāng)虛擬機(jī)收到一條new指令時(shí),首先去檢查這個(gè)指令的參數(shù)能否在常量池中定位到對(duì)應(yīng)的符號(hào)引用,并且檢查符號(hào)引用代表的類是否加載過、解析和初始化過,沒有則進(jìn)行對(duì)應(yīng)的類加載過程。

2.在類檢查通過后,虛擬機(jī)為新生對(duì)象從Java堆中分配內(nèi)存。而內(nèi)存的分配又有兩種方式。一種是指針碰撞,就是把空閑和正在使用的內(nèi)存中間放一個(gè)指針隔開,所以這種方式實(shí)際就是把指針進(jìn)行移動(dòng),當(dāng)內(nèi)存出現(xiàn)相互交錯(cuò)時(shí)。該方式自然就行不通了;另一種方式是空閑列表,由虛擬機(jī)維護(hù)一個(gè)列表,分配內(nèi)存后就更新這個(gè)列表的記錄。至于使用哪種方式就要看是基于何種垃圾回收器而言。除了怎么劃分可用空間之外,還需要考慮虛擬機(jī)分配內(nèi)存的頻率,分配頻率就會(huì)涉及到并發(fā)中的一些問題了。JVM采用CAS(比較并交換)方式進(jìn)行失敗重試保證操作的原子性;另一種是每個(gè)線程在Java堆中預(yù)先分配一小塊內(nèi)存,也就是本地線程分配緩沖(TLAB)

3.內(nèi)存分配完成后,虛擬機(jī)將分配到的內(nèi)存空間都初始化為零值,使用TLAB,則可以提前到分配時(shí)進(jìn)行。

4.虛擬機(jī)對(duì)對(duì)象進(jìn)行必要的設(shè)置,也就是把該對(duì)象相關(guān)的信息存儲(chǔ)在對(duì)象頭之中,這些工作都完成后,一個(gè)新的對(duì)象已經(jīng)產(chǎn)生了,接下來(lái)就是對(duì)象的初始化了。

對(duì)象的訪問定位

對(duì)象的訪問目前主流的方式有句柄和直接指針兩種。
1.使用句柄訪問,Java堆會(huì)劃分出一塊內(nèi)存作為句柄池,對(duì)象的引用中存儲(chǔ)的就是其句柄的地址,句柄包含了對(duì)象實(shí)例數(shù)據(jù)和類型數(shù)據(jù)的具體地址信息。
2.使用直接指針,堆就要考慮如何放置訪問類型數(shù)據(jù)相關(guān)的信息,引用中存儲(chǔ)的直接就是對(duì)象地址。
很顯然,因?yàn)槭侵苯又赶虻刂?,所以直接指針的方式更加快,但?duì)象訪問在Java中太過頻繁,積少成多后也會(huì)造成較高的執(zhí)行成本。

內(nèi)存溢出異常 1.Java堆溢出
public class HeapOOM {

    static class OOMObject {

    }

    public static void main(String[] args) {
        List list = new ArrayList<>();
        while (true) {
            list.add(new OOMObject());
        }
    }
}

這里可以設(shè)置下虛擬機(jī)相關(guān)的參數(shù),

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
2.虛擬機(jī)和本地方法棧溢出
public class JavaVMStackSOF {

    private int stackLength = 1;
    public void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        JavaVMStackSOF stackSOF = new JavaVMStackSOF();

        try {
            stackSOF.stackLeak();
        } catch (Throwable e) {
            System.out.println("Stack length: "+stackSOF.stackLength );
            throw e;
        }
    }
}
3.創(chuàng)建線程導(dǎo)致的內(nèi)存溢出
public class JavaVMStackOOM {

    private void doStop() {
        while (true) {

        }
    }

    public void stackLeakByThread() {
        while (true) {
            Thread thread = new Thread(()->{
               doStop();
            });
            thread.start();
        }
    }

    public static void main(String[] args) {
        JavaVMStackOOM oom = new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}

這里的話,在Windows平臺(tái)的虛擬機(jī)中,Java的線程是映射到操作系統(tǒng)的內(nèi)核線程上,這里可能導(dǎo)致機(jī)器假死。

4.方法和運(yùn)行時(shí)常量池溢出
public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {
        List list = new ArrayList<>();
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
        }
    }
}
5.本機(jī)直接內(nèi)存溢出
public class DirectMemoryOOM {

    public static final int _1MB = 1024 * 1024;
    public static void main(String[] args) {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        try {
            Unsafe unsafe = (Unsafe) unsafeField.get(null);
            while (true) {
                unsafe.allocateMemory(_1MB);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
總結(jié)

了解了這些不得不佩服設(shè)計(jì)者,一個(gè)看似簡(jiǎn)單的東西底層要解決的問題、處理的細(xì)節(jié)也是非常多的,從Java虛擬機(jī)層面看到了不一樣的東西,也是非常有意思的,理解底層實(shí)現(xiàn)的原理有助于寫成更健壯的代碼,更快速的debug,就到這里了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/71073.html

相關(guān)文章

  • 十種JVM內(nèi)存溢出的情況,你碰到過幾種?

    摘要:內(nèi)存溢出的情況就是從類加載器加載的時(shí)候開始出現(xiàn)的,內(nèi)存溢出分為兩大類和。以下舉出個(gè)內(nèi)存溢出的情況,并通過實(shí)例代碼的方式講解了是如何出現(xiàn)內(nèi)存溢出的。內(nèi)存溢出問題描述元空間的溢出,系統(tǒng)會(huì)拋出。這樣就會(huì)造成棧的內(nèi)存溢出。 導(dǎo)言: 對(duì)于java程序員來(lái)說(shuō),在虛擬機(jī)自動(dòng)內(nèi)存管理機(jī)制的幫助下,不需要自己實(shí)現(xiàn)釋放內(nèi)存,不容易出現(xiàn)內(nèi)存泄漏和內(nèi)存溢出的問題,由虛擬機(jī)管理內(nèi)存這一切看起來(lái)非常美好,但是一旦...

    ShevaKuilin 評(píng)論0 收藏0
  • Java虛擬機(jī)筆記-內(nèi)存區(qū)內(nèi)存溢出

    摘要:小結(jié)程序計(jì)數(shù)器和虛擬機(jī)棧是線程私有的,而堆和方法區(qū)是線程共享的除了虛擬機(jī)運(yùn)行時(shí)內(nèi)存,在中使用類可以直接操作本機(jī)內(nèi)存。 Java的內(nèi)存區(qū)域 Java虛擬機(jī)在執(zhí)行Java程序中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)數(shù)據(jù)區(qū)域,這些區(qū)域有各自的用途,以及生命周期,有些依賴虛擬機(jī)進(jìn)程啟動(dòng)而存在,有些依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀 運(yùn)行時(shí)內(nèi)存 showImg(/img/bVqUpc); 程序計(jì)數(shù)器(...

    Ocean 評(píng)論0 收藏0
  • Java內(nèi)存區(qū)域內(nèi)存溢出

    摘要:直接通過可以造成本機(jī)內(nèi)存溢出。小節(jié)內(nèi)存區(qū)域描述異常程序計(jì)數(shù)器略略略虛擬機(jī)棧存放編譯器可知的各種基本類型,對(duì)象引用和類型每個(gè)線程的棧大小堆存放對(duì)象實(shí)例最大值最小值運(yùn)行時(shí)常亮池存放編譯期生成的字面量和符號(hào)引用,運(yùn)行期也能放入常量池。 堆溢出 Java堆用于存儲(chǔ)對(duì)象實(shí)例,只要不斷地創(chuàng)建對(duì)象,并且保證GC Roots到對(duì)象之間有可達(dá)路徑避免垃圾回收,當(dāng)?shù)竭_(dá)最大堆的容量限制后就會(huì)產(chǎn)生Java.l...

    cheukyin 評(píng)論0 收藏0
  • JVM系列(一):深入詳解JVM 內(nèi)存區(qū)域總結(jié)!

    摘要:一內(nèi)存區(qū)域虛擬機(jī)在運(yùn)行時(shí),會(huì)把內(nèi)存空間分為若干個(gè)區(qū)域,根據(jù)虛擬機(jī)規(guī)范版的規(guī)定,虛擬機(jī)所管理的內(nèi)存區(qū)域分為如下部分方法區(qū)堆內(nèi)存虛擬機(jī)棧本地方法棧程序計(jì)數(shù)器。前言 在JVM的管控下,Java程序員不再需要管理內(nèi)存的分配與釋放,這和在C和C++的世界是完全不一樣的。所以,在JVM的幫助下,Java程序員很少會(huì)關(guān)注內(nèi)存泄露和內(nèi)存溢出的問題。但是,一旦JVM發(fā)生這些情況的時(shí)候,如果你不清楚JVM內(nèi)存的...

    Aldous 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<