最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一篇文章帶你了解JVM內(nèi)存模型

 更新時間:2021年09月17日 14:39:11   作者:華為云  
本文講解了Java 內(nèi)存模型來看看解決可見性、有序性問題的 Java 內(nèi)存模型(JMM),今天通過本文給大家介紹Java 內(nèi)存模型(JVM)的相關(guān)知識,感興趣的朋友一起看看吧

1. JVM介紹 

1.1 什么是JVM?

JVM是Java Virtual Machine(Java虛擬機)的簡稱,是一種用于計算設備的規(guī)范,是一個虛構(gòu)出來的計算機,通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的。

1.2 JVM的優(yōu)點 

1.2.1 一次編寫,到處運行。

JVM可以讓java程序,一次編寫,導出運行。讓底層代碼和運行環(huán)境分離開,編寫好一份代碼后,不用再次修改內(nèi)容,只用通過安裝不同的JVM環(huán)境自動進行轉(zhuǎn)換即可運行,在各種系統(tǒng)中無縫連接。

1.2.2 自動內(nèi)存管理,垃圾回收機制。

在Java誕生之時,C和C++稱霸天下,但是這兩種語言中沒有內(nèi)存管理機制,是通過手動操作來進行的管理,非常麻煩和繁瑣。

此時Java應運而生,為了處理內(nèi)存管理這個方面,專門設計了垃圾回收機制,來自動進行內(nèi)存的管理。極大的優(yōu)化了操作,讓程序員們不用正在噼里啪啦在碼代的海洋中遨游時,還要操心內(nèi)存會不會溢出這些“影響我方輸出”的問題,頓時獲得了成噸的好評。

1.2.3 數(shù)組下標越界檢查

在Java誕生之時,還有個讓當時C和C++大佬頭疼的問題是,數(shù)組下標越界是沒有檢查機制的,這還了得,又是一個影響“我方暴力輸出”的罪魁禍首,因此JVM繼續(xù)抱著暖男的思想,又來了個愛的抱抱。

JVM又一次看見了大佬們的煩惱,果斷提供了數(shù)組下標越界的自動檢查機制,在檢測到數(shù)組下標出現(xiàn)越界后,會在運行時自動拋出“java.lang.ArrayIndexOutOfBoundsException”這個異常,在當時可是感動了很多業(yè)界大佬(我猜的)。

1.2.4 多態(tài)

JVM還有一個多態(tài)功能,是通過相同接口,不同的實例進行實現(xiàn),完成不同的業(yè)務操作,比如:定義了一個動物接口(里面有一個吃的方法),我們就可以通過這個動物創(chuàng)造小貓(吃魚),再創(chuàng)造一個狗狗(吃肉),再創(chuàng)造一個小助手(吃零食,O(∩_∩)O哈哈~)。

仔細想想,對我們有啥影響呢,那好處老多了,比如:

(1)消除類型之間的耦合關(guān)系;

(2)可替換性;

(3)可擴充性;

(4)接口性;

(5)靈活性;

(6)簡化性;

1.3 JVM、JRE、JDK之間的關(guān)系 

1.3.1 JVM的簡介

JVM是Java Virtual Machine的簡稱,是Java虛擬機,是一種模擬出來的虛擬計算機,它通過在不同的計算機環(huán)境當中模擬實現(xiàn)計算功能來實現(xiàn)的。

引入Java虛擬機后,Java語言在不同平臺上運行時就不需要重新編譯。在其中,Java虛擬機屏蔽了與具體平臺的相關(guān)信息,使得Java源程序在編譯完成之后即可在不同的平臺運行,達到“一次編譯,到處運行”的目的,Java語言重要的特點之一跨平臺,也即與平臺的無關(guān)性,其關(guān)鍵點就是JVM。

1.3.2 JRE的簡介

JRE是Java Runtime Environment的簡稱,是Java運行環(huán)境,是讓操作系統(tǒng)運行Java應用程序的環(huán)境,其內(nèi)部包含JVM,也就是說JRE只負責對已經(jīng)存在的Java源程序進行運行的操作,它不包含開發(fā)工具JDK,對JDK內(nèi)部的編譯器、調(diào)試器和其它工具均不包含。

1.3.3 JDK的簡介

JDK是Java Development Kit的簡稱,是Java開發(fā)工具包,是整個Java程序開發(fā)的核心。其主要包含了JRE、Java的系統(tǒng)類庫以及對Java程序進行編譯以及運行的工具,例如:javac.exe和java.exe命令工具等。

1.4 JVM的常見實現(xiàn)

Oracle(Hotspot、Jrockit)、BEA(LiquidVM)、IBM(J9)、taobaoVM(淘寶專用,對Hotspot進行了深度定制)、zing(垃圾回收機制非???,到達1毫秒左右)。

1.5 JVM的內(nèi)存結(jié)構(gòu)圖

當Java程序編譯完成為.class文件==》類加載器(ClassLoader)==》將字節(jié)碼文件加載進JVM中;

1.5.1方法區(qū)、堆

方法區(qū)中保存的主要是類的信息(類的屬性、成員變量、構(gòu)造函數(shù)等)、堆(創(chuàng)建的對象)。

1.5.2虛擬機棧、程序計數(shù)器、本地方法棧

堆中的對象調(diào)用方法時,方法會運行在虛擬機棧、程序計數(shù)器、本地方法棧中。

1.5.3執(zhí)行引擎

執(zhí)行方法中代碼時,代碼通過執(zhí)行引擎執(zhí)行中的“解釋器”執(zhí)行;方法中經(jīng)常調(diào)用的代碼,即熱點代碼,通過“即時編譯器”執(zhí)行,其執(zhí)行速度非???。

1.5.4 GC(垃圾回收機制)

GC是針對堆內(nèi)存中沒有引用的對象進行回收,可以手動也可以自動。

1.5.5本地方法接口

因為JVM不能直接調(diào)用操作系統(tǒng)的功能,只能通過本地方法接口來調(diào)用操作系統(tǒng)的功能。

2. JVM內(nèi)存結(jié)構(gòu)-程序計數(shù)器 

2.1 程序計數(shù)器的定義

Program Counter Register即程序計數(shù)器(寄存器),用于記錄下一條Jvm指令的執(zhí)行地址。

2.2 操作步驟

javap主要用于操作JVM,javap -c 是對java代碼進行反匯編操作。下圖為通過先編譯demo.java后,再執(zhí)行javap -c demo的輸出結(jié)果:

其中第一列為二進制字節(jié)碼,即JVM指令,第二列為java源代碼。第一列中的序號為JVM指令的執(zhí)行地址。

JVM會通過程序計數(shù)器記錄下一條需要執(zhí)行的JVM指令的地址(比如第一行的0),然后交給解釋器解析為機器碼,最后交給cpu(只能識別機器碼),完成一行的執(zhí)行。

想要執(zhí)行下一行,繼續(xù)讓JVM的程序計數(shù)器記錄下一條地址(比如第二行的3),再交給解釋器解析后給cpu,以此類推執(zhí)行結(jié)束。

2.3 特點 

2.3.1 線程私有的 

2.3.2 不會存在內(nèi)存溢出 

3. JVM內(nèi)存結(jié)構(gòu)-虛擬機棧 

3.1 定義

虛擬機棧是每個線程運行所需要的內(nèi)存空間,每個棧中由多個棧幀組成,每個線程中只能有一個活動棧幀(對應當前正在執(zhí)行的方法),所有棧幀都遵循后進先出,先進后出的原則。

棧幀是每次調(diào)用方法時所占用的內(nèi)存,在棧幀中保存的內(nèi)容參數(shù)、局部變量、返回地址。

注1:垃圾回收不涉及棧內(nèi)存,因為棧內(nèi)存是由方法調(diào)用產(chǎn)生的,當方法調(diào)用結(jié)束后會彈出棧。

注2:棧內(nèi)存不是分配的越大越好,因為物理內(nèi)存是一定的,棧內(nèi)存越大,可以支持更多的遞歸調(diào)用,但是可執(zhí)行的線程數(shù)會越來越少。

注3:方法的局部變量,當其沒有逃離方法的作用范圍時,是線程安全的;如果其引用了對象(比如靜態(tài)變量,即共享變量,用對象作為參數(shù)的方法,返回值為對象的方法),并且逃離出了方法的作用范圍,就需要考慮線程安全的問題了。

3.2 棧內(nèi)存溢出

3.2.1 發(fā)生原因

(1)虛擬機棧中,棧幀過多(無限遞歸),如圖1棧幀過多;

(2)每個棧幀所占用過大,如圖2 棧幀過大。

3.2.2 棧內(nèi)存溢出小實驗

3.2.2.1 棧幀過多的小實驗

無限遞歸調(diào)用(棧幀過多)的小實驗,method1()方法在主方法中無限調(diào)用自己,那么會發(fā)生什么情況呢?

答案很明顯,程序崩潰了,產(chǎn)生了棧內(nèi)存溢出錯誤,如下圖所示:

-Xss:該參數(shù)規(guī)定了每個線程虛擬機棧的大小;

接著我們通過設置一個虛擬機棧的大小是256k試試會發(fā)生什么?

我們發(fā)現(xiàn)當我們調(diào)整了虛擬機棧的大小后執(zhí)行了4315次方法后內(nèi)存就溢出了,而調(diào)整虛擬機棧之前,我們是23268次,很明顯我們可以通過-Xss參數(shù)調(diào)整虛擬機棧的大小來控制內(nèi)存的溢出情況。

3.2.2.2 線程運行診斷小實驗

想象中的場景,大佬在瘋狂輸出,突然CPU爆表了,顯示CPU占用過多,如何去定位哪行代碼的問題,是的是哪行(大佬都很忙的好嗎,當然要精確了,一分鐘幾千萬上下的,O(∩_∩)O哈哈~)?

Linux環(huán)境下:

在后臺運行Stack_6這個java字節(jié)碼(.class)文件:

注:無論是否將nohup命令的輸出重定向到終端,輸出都將附加到當前目錄的 nohup.out 文件中。

(1)通過top命令,查看進程(相當于任務管理器),發(fā)現(xiàn)了一個占用CPU達到100%的可疑家伙,這還了得,趕緊瞅瞅具體發(fā)生了什么,還有沒有王法,這讓其他小伙伴還怎么愉快的玩耍,秒速糾錯ING。。。

注:top命令,查看哪個進程占用CPU過高,返回進程號。

(2) 通過ps H -eo pid,tid ,%cpu | grep 命令過濾任務管理器中的內(nèi)容。

注:ps H -eo pid,tid,%cpu |grep,是通過ps命令查看哪個線程占用CPU過高,返回進程id,其中pid為進程id,tid為線程id,%cpu為CPU占用情況;

發(fā)現(xiàn)了罪魁禍首,這一串串心驚肉跳的紅色。。。

(3) 通過jstack 進程id查看,20389這個有問題的進程中具體的情況。

注:jstack 進程id,是通過jstack 命令定位具體哪段代碼出現(xiàn)占用CPU過高,注意jstack命令查找的線程id是16進制的,需要轉(zhuǎn)換;

發(fā)現(xiàn)里面有一堆執(zhí)行的代碼,那么我們怎么找到具體是哪個家伙搞事情的呢?上圖我們可以發(fā)現(xiàn)搞事情的線程是20441,那么我們通過計算器將20441轉(zhuǎn)換為16進制的4FD9再去試試,真相只有一個。

通過對比nid(線程id)4fd9,我們發(fā)現(xiàn)這個叫thread1的線程一直在運行(RUNNABLE狀態(tài)),并且查看到位置是位于Stack_6.java文件的第11行出現(xiàn)的問題。。。

現(xiàn)在我們回到源碼中,在Stack_6文件的第11行,我們發(fā)現(xiàn)原來這里一直在執(zhí)行死循環(huán),終于找到你,還好我沒放棄,奈斯~

4. JVM內(nèi)存結(jié)構(gòu)-本地方法棧 

4.1 定義

由于Java本身有時候是無法直接和操作系統(tǒng)底層交互的,但有時候需要Java調(diào)用本地的C或C++方法,所以此時本地方法棧應運而生,它們是一類帶有native關(guān)鍵字的方法。

5. JVM內(nèi)存結(jié)構(gòu)-堆 

5.1 定義

Heap堆:是通過new關(guān)鍵字創(chuàng)建的對象存放在堆中

5.2 特點 

5.2.1線程共享

堆中存放的對象都是線程共享的,因此都是需要考慮線程安全問題的。

5.2.2有垃圾回收機制

因為堆中存放的對象存放了大量的對象,因此給他配了個小助手——垃圾回收機制(可以調(diào)自動擋和手動擋哦~)。

5.3 堆內(nèi)存溢出小實驗 

5.3.1 修改堆內(nèi)存大小參數(shù)的小實驗

繼續(xù)幻想一個場景,當一個大佬開發(fā)完一個段代碼的時候(當然一般大佬都是很自信的,我寫的代碼怎么可能有問題,不存在的。。。),但是測試可跑不了,穩(wěn)妥起見咱們還是默默得搞測試試試嘛,安全第一。但是機器的內(nèi)存就這么大,大佬肯定跑了很多次了,都沒出現(xiàn)問題的,這不是找茬嘛。。。還是默默改下機子參數(shù)再試試吧(想去懟大佬,一定要拿出證據(jù)嘛~)。

-Xmx:JVM調(diào)優(yōu)參數(shù)之一,該參數(shù)表示java堆可以擴展到的最大值。下面上案例:

在執(zhí)行了26次之后,果斷的后臺報了堆內(nèi)存溢出錯誤。

下面通過-Xmx JVM調(diào)優(yōu)參數(shù)將堆內(nèi)存調(diào)小至8m,再試試會發(fā)生什么呢?

操作基本和棧內(nèi)存溢出的時候的案例一樣,次數(shù)明顯變小了,只調(diào)用了17次就出現(xiàn)了堆內(nèi)存溢出錯誤了。

5.3.2 堆內(nèi)存診斷的小實驗

jps工具:查看當前系統(tǒng)中有哪些java進程

jmap工具:查看堆內(nèi)存的占用情況jmap -heap 進程id

jconsole工具:圖形化的工具,擁有多功能的監(jiān)測功能,可以連續(xù)監(jiān)測。

下面我們通過運行代碼后通過jconsole可視化圖形工具,來查看堆內(nèi)存的使用情況。

上圖我們可以看到,在我們創(chuàng)建10mb的數(shù)組對象時,內(nèi)存使用有一定上升;然后在我們手動調(diào)用垃圾回收機制后,內(nèi)存又得到了很大的釋放。

6. JVM內(nèi)存結(jié)構(gòu)-方法區(qū) 

6.1 定義

Java虛擬機中有一個被所有jvm線程共享的方法區(qū)。方法區(qū)有點類似于傳統(tǒng)編程語言中的編譯代碼塊或者操作系統(tǒng)層面的代碼段。它存儲著每個類的構(gòu)造信息,譬如運行時的常量池,字段,方法數(shù)據(jù),以及方法和構(gòu)造方法的代碼,包括一些在類和實例初始化和接口初始化時候使用的特殊方法。

方法區(qū)有個別稱non-heap(非堆),可以看作是一塊獨立于堆的內(nèi)存空間,是JVM規(guī)范中定義的一個概念,用于存儲類信息、常量池、靜態(tài)變量,JIT編譯后的代碼等數(shù)據(jù),具體放在哪里,不同的實現(xiàn)可以放在不同的地方。

6.2 特點

(1)方法區(qū)與java堆一樣,是各個線程共享的內(nèi)存區(qū)域;

(2)方法區(qū)在JVM啟動的時候被創(chuàng)建;

(3)方法區(qū)的大小,跟堆空間一樣,可以選擇固定大小或擴展;

(4)方法區(qū)的大小決定了系統(tǒng)可以保存多少個類,如果系統(tǒng)定義了太多的類,導致方法區(qū)溢出,虛擬機同樣會拋出溢出錯誤OutOfMemoryError;

(5)關(guān)閉JVM就會釋放這個區(qū)域的內(nèi)存。

6.3 JVM內(nèi)存結(jié)構(gòu)示意圖

在JVM內(nèi)存結(jié)構(gòu)1.6的時候,方法區(qū)保存在內(nèi)存結(jié)構(gòu)中,叫做永久代,里面存儲了運行時的常量池(包含串池StringTable)、類的信息、類加載器;

在JVM內(nèi)存結(jié)構(gòu)1.8的時候,方法區(qū)做為一個概念,保存在本地內(nèi)存中,叫做元空間,里面存儲了運行時的常量池、類的信息、類加載器,此時串池(StringTable)儲存在堆之中。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • maven導入本地倉庫jar包,報:Could?not?find?artifact的解決

    maven導入本地倉庫jar包,報:Could?not?find?artifact的解決

    這篇文章主要介紹了maven導入本地倉庫jar包,報:Could?not?find?artifact的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 實例講解Java設計模式編程中的OCP開閉原則

    實例講解Java設計模式編程中的OCP開閉原則

    這篇文章主要介紹了Java設計模式編程中的開閉原則,開閉原則的大意被作者總結(jié)為用抽象構(gòu)建框架,用實現(xiàn)擴展細節(jié),需要的朋友可以參考下
    2016-02-02
  • 使用Spring?Security搭建極簡的安全網(wǎng)站教程

    使用Spring?Security搭建極簡的安全網(wǎng)站教程

    這篇文章主要為大家介紹了使用Spring?Security搭建極簡的安全網(wǎng)站教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Java使用Collections.sort對中文進行排序方式

    Java使用Collections.sort對中文進行排序方式

    這篇文章主要介紹了Java使用Collections.sort對中文進行排序方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java計算集合對稱差的示例代碼

    java計算集合對稱差的示例代碼

    本篇文章主要介紹了java計算集合對稱差的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Java中定時器Timer致命缺點案例詳解

    Java中定時器Timer致命缺點案例詳解

    這篇文章主要介紹了Java中定時器Timer致命缺點,以Java中定時器Time為案例整理下我的學習方法,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • TCP/IP協(xié)議中三次握手四次揮手的原理及流程分析

    TCP/IP協(xié)議中三次握手四次揮手的原理及流程分析

    這篇文章主要介紹了TCP/IP協(xié)議中三次握手四次揮手的原理及流程分析,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • 解析Java定時任務的選型及改造問題

    解析Java定時任務的選型及改造問題

    這篇文章主要介紹了Java定時任務的選型及改造問題,本文給大家提到了Java主流三大定時任務框架優(yōu)缺點,通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • Java線程中的Thread.yield()詳細解析

    Java線程中的Thread.yield()詳細解析

    這篇文章主要介紹了Java線程中的Thread.yield()詳細解析,yield()讓當前線程從運行狀態(tài)?轉(zhuǎn)為?就緒狀態(tài),以允許具有相同優(yōu)先級的其他線程獲得運行機會,需要的朋友可以參考下
    2023-11-11
  • Java SPI模塊化解耦的技術(shù)指南

    Java SPI模塊化解耦的技術(shù)指南

    Java 的 Service Provider Interface (SPI) 是一種提供模塊化和擴展性的方法,使得程序能夠通過動態(tài)加載服務實現(xiàn)類來實現(xiàn)解耦,本文將詳細介紹 Java SPI 的機制、應用場景及實現(xiàn)步驟,并通過示例代碼展示如何使用 SPI,需要的朋友可以參考下
    2025-03-03

最新評論

浦北县| 成安县| 永安市| 宜宾市| 佳木斯市| 武穴市| 中江县| 嘉义县| 故城县| 七台河市| 北票市| 永靖县| 庆云县| 台湾省| 涞水县| 南宁市| 和政县| 临邑县| 闵行区| 汉川市| 林甸县| 建昌县| 宝山区| 突泉县| 土默特左旗| 定结县| 上饶市| 抚松县| 东乌珠穆沁旗| 左贡县| 昌邑市| 建始县| 宁化县| 赤城县| 盐城市| 大英县| 东乌珠穆沁旗| 绥宁县| 略阳县| 兴山县| 宽城|