吴忠躺衫网络科技有限公司

您好,歡迎來電子發(fā)燒友網(wǎng)! ,新用戶?[免費注冊]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>java源碼下載>

java虛擬機常見問題

大小:0.5 MB 人氣: 2017-09-27 需要積分:3

  

  一、Java引用的四種狀態(tài):

  強引用:

  用的最廣。我們平時寫代碼時,new一個Object存放在堆內(nèi)存,然后用一個引用指向它,這就是強引用。

  *  如果一個對象具有強引用,那垃圾回收器絕不會回收它*。當內(nèi)存空間不足,Java虛擬機寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內(nèi)存不足的問題。

  軟引用:

  如果一個對象只具有軟引用,則內(nèi)存空間足夠時,垃圾回收器就不會回收它;如果內(nèi)存空間不足了,就會回收這些對象的內(nèi)存。(備注:如果內(nèi)存不足,隨時有可能被回收。)

  只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現(xiàn)內(nèi)存敏感的高速緩存。

  弱引用:

  弱引用與軟引用的區(qū)別在于:只具有弱引用的對象擁有更短暫的生命周期。

  *  每次執(zhí)行GC的時候,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當前內(nèi)存空間足夠與否,都會回收它的內(nèi)存。不過,由于垃圾回收器是一個優(yōu)先級很低的線程,因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象*。

  虛引用:

  “虛引用”顧名思義,就是形同虛設(shè),與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

  虛引用主要用來跟蹤對象被垃圾回收器回收的活動。

  注:關(guān)于各種引用的詳解,可以參考這篇博客:

  http://zhangjunhd.blog.51cto.com/113473/53092

  二、Java中的內(nèi)存劃分:

  Java程序在運行時,需要在內(nèi)存中的分配空間。為了提高運算效率,就對數(shù)據(jù)進行了不同空間的劃分,因為每一片區(qū)域都有特定的處理數(shù)據(jù)方式和內(nèi)存管理方式。

  java虛擬機常見問題

  上面這張圖就是jvm運行時的狀態(tài)。具體劃分為如下5個內(nèi)存空間:(非常重要)

  - 程序計數(shù)器:保證線程切換后能恢復到原來的執(zhí)行位置

  - 虛擬機棧:(棧內(nèi)存)為虛擬機執(zhí)行java方法服務(wù):方法被調(diào)用時創(chuàng)建棧幀–》局部變量表-》局部變量、對象引用

  - 本地方法棧:為虛擬機執(zhí)使用到的Native方法服務(wù)

  - 堆內(nèi)存:存放所有new出來的東西

  - 方法區(qū):存儲被虛擬機加載的類信息、常量、靜態(tài)常量、靜態(tài)方法等。

  - 運行時常量池(方法區(qū)的一部分)

  GC對它們的回收:

  內(nèi)存區(qū)域中的程序計數(shù)器、虛擬機棧、本地方法棧這3個區(qū)域隨著線程而生,線程而滅;棧中的棧幀隨著方法的進入和退出而有條不紊地執(zhí)行著出棧和入棧的操作,每個棧幀中分配多少內(nèi)存基本是在類結(jié)構(gòu)確定下來時就已知的。在這幾個區(qū)域不需要過多考慮回收的問題,因為方法結(jié)束或者線程結(jié)束時,內(nèi)存自然就跟著回收了。

  GC回收的主要對象:而J**ava堆和方法區(qū)**則不同,一個接口中的多個實現(xiàn)類需要的內(nèi)存可能不同,一個方法中的多個分支需要的內(nèi)存也可能不一樣,我們只有在程序處于運行期間時才能知道會創(chuàng)建哪些對象,這部分內(nèi)存的分配和回收都是動態(tài)的,GC關(guān)注的也是這部分內(nèi)存,后面的文章中如果涉及到“內(nèi)存”分配與回收也僅指著一部分內(nèi)存。

  1、程序計數(shù)器:(線程私有)

  每個線程擁有一個程序計數(shù)器,在線程創(chuàng)建時創(chuàng)建,

  指向下一條指令的地址

  執(zhí)行本地方法時,其值為undefined

  說的通俗一點,我們知道,Java是支持多線程的,程序先去執(zhí)行A線程,執(zhí)行到一半,然后就去執(zhí)行B線程,然后又跑回來接著執(zhí)行A線程,那程序是怎么記住A線程已經(jīng)執(zhí)行到哪里了呢?這就需要程序計數(shù)器了。因此,為了線程切換后能夠恢復到正確的執(zhí)行位置,每條線程都有一個獨立的程序計數(shù)器,這塊兒屬于“線程私有”的內(nèi)存。

  2、Java虛擬機棧:(線程私有)

  每個方法被調(diào)用的時候都會創(chuàng)建一個棧幀,用于存儲局部變量表、操作棧、動態(tài)鏈接、方法出口等信息。局部變量表存放的是:編譯期可知的基本數(shù)據(jù)類型、對象引用類型。

  每個方法被調(diào)用直到執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機中從入棧到出棧的過程。

  在Java虛擬機規(guī)范中,對這個區(qū)域規(guī)定了兩種異常情況:

  (1)如果線程請求的棧深度太深,超出了虛擬機所允許的深度,就會出現(xiàn)StackOverFlowError(比如無限遞歸。因為每一層棧幀都占用一定空間,而 Xss 規(guī)定了棧的最大空間,超出這個值就會報錯)

  (2)虛擬機棧可以動態(tài)擴展,如果擴展到無法申請足夠的內(nèi)存空間,會出現(xiàn)OOM

  3、本地方法棧:

  (1)本地方法棧與java虛擬機棧作用非常類似,其區(qū)別是:java虛擬機棧是為虛擬機執(zhí)行java方法服務(wù)的,而本地方法棧則為虛擬機執(zhí)使用到的Native方法服務(wù)。

  (2)Java虛擬機沒有對本地方法棧的使用和數(shù)據(jù)結(jié)構(gòu)做強制規(guī)定,Sun HotSpot虛擬機就把java虛擬機棧和本地方法棧合二為一。

  (3)本地方法棧也會拋出StackOverFlowError和OutOfMemoryError。

  4、Java堆:即堆內(nèi)存(線程共享)

  (1)堆是java虛擬機所管理的內(nèi)存區(qū)域中最大的一塊,java堆是被所有線程共享的內(nèi)存區(qū)域,在java虛擬機啟動時創(chuàng)建,堆內(nèi)存的唯一目的就是存放對象實例幾乎所有的對象實例都在堆內(nèi)存分配。

  (2)堆是GC管理的主要區(qū)域,從垃圾回收的角度看,由于現(xiàn)在的垃圾收集器都是采用的分代收集算法,因此java堆還可以初步細分為新生代和老年代。

  (3)Java虛擬機規(guī)定,堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上連續(xù)的即可。在實現(xiàn)上既可以是固定的,也可以是可動態(tài)擴展的。如果在堆內(nèi)存沒有完成實例分配,并且堆大小也無法擴展,就會拋出OutOfMemoryError異常。

  5、方法區(qū):(線程共享)

  (1)用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。

  (2)Sun HotSpot虛擬機把方法區(qū)叫做永久代(Permanent Generation),方法區(qū)中最終要的部分是運行時常量池。

  6、運行時常量池:

  (1)運行時常量池是方法區(qū)的一部分,自然受到方法區(qū)內(nèi)存的限制,當常量池無法再申請到內(nèi)存時就會拋出OutOfMemoryError異常。

  三、Java對象在內(nèi)存中的狀態(tài):

  可達的/可觸及的:

  Java對象被創(chuàng)建后,如果被一個或多個變量引用,那就是可達的。即從根節(jié)點可以觸及到這個對象。

  其實就是從根節(jié)點掃描,只要這個對象在引用鏈中,那就是可觸及的。

  可恢復的:

  Java對象不再被任何變量引用就進入了可恢復狀態(tài)。

  在回收該對象之前,該對象的finalize()方法進行資源清理。如果在finalize()方法中重新讓變量引用該對象,則該對象再次變?yōu)榭蛇_狀態(tài),否則該對象進入不可達狀態(tài)

  不可達的:

  Java對象不被任何變量引用,且系統(tǒng)在調(diào)用對象的finalize()方法后依然沒有使該對象變成可達狀態(tài)(該對象依然沒有被變量引用),那么該對象將變成不可達狀態(tài)。

  當Java對象處于不可達狀態(tài)時,系統(tǒng)才會真正回收該對象所占有的資源。

  四、判斷對象死亡的兩種常用算法:

  當對象不被引用的時候,這個對象就是死亡的,等待GC進行回收。

  1、引用計數(shù)算法:

  概念:

  給對象中添加一個引用計數(shù)器,每當有一個地方引用它時,計數(shù)器值就加1;當引用失效時,計數(shù)器值就減1;任何時刻計數(shù)器為0的對象就是不可能再被使用的。

  但是:

  主流的java虛擬機并沒有選用引用計數(shù)算法來管理內(nèi)存,其中最主要的原因是:它很難解決對象之間相互循環(huán)引用的問題。

  優(yōu)點:

  算法的實現(xiàn)簡單,判定效率也高,大部分情況下是一個不錯的算法。很多地方應(yīng)用到它

  缺點:

  引用和去引用伴隨加法和減法,影響性能

  致命的缺陷:對于循環(huán)引用的對象無法進行回收

  2、根搜索算法:(jvm采用的算法)

  概念:

  設(shè)立若干種根對象,當任何一個根對象(GC Root)到某一個對象均不可達時,則認為這個對象是可以被回收的。

  注:這里提到,設(shè)立若干種根對象,當任何一個根對象到某一個對象均不可達時,則認為這個對象是可以被回收的。我們在后面介紹標記-清理算法/標記整理算法時,也會一直強調(diào)從根節(jié)點開始,對所有可達對象做一次標記,那什么叫做可達呢?

  可達性分析:

  從根(GC Roots)的對象作為起始點,開始向下搜索,搜索所走過的路徑稱為“引用鏈”,當一個對象到GC Roots沒有任何引用鏈相連(用圖論的概念來講,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的。

  java虛擬機常見問題

  如上圖所示,ObjectD和ObjectE是互相關(guān)聯(lián)的,但是由于GC roots到這兩個對象不可達,所以最終D和E還是會被當做GC的對象,上圖若是采用引用計數(shù)法,則A-E五個對象都不會被回收。

  根(GC Roots):

  說到GC roots(GC根),在JAVA語言中,可以當做GC roots的對象有以下幾種:

  1、棧(棧幀中的本地變量表)中引用的對象。

  2、方法區(qū)中的靜態(tài)成員。

  3、方法區(qū)中的常量引用的對象(全局變量)

  4、本地方法棧中JNI(一般說的Native方法)引用的對象。

  注:第一和第四種都是指的方法的本地變量表,第二種表達的意思比較清晰,第三種主要指的是聲明為final的常量值。

  在根搜索算法的基礎(chǔ)上,現(xiàn)代虛擬機的實現(xiàn)當中,垃圾搜集的算法主要有三種,分別是標記-清除算法、復制算法、標記-整理算法。這三種算法都擴充了根搜索算法,不過它們理解起來還是非常好理解的。

非常好我支持^.^

(0) 0%

不好我反對

(0) 0%

      發(fā)表評論

      用戶評論
      評價:好評中評差評

      發(fā)表評論,獲取積分! 請遵守相關(guān)規(guī)定!

      ?
      银泰娱乐城| 温州百家乐官网真人网| 百家乐官网龙虎的投注法| 北京百家乐网上投注| 吉隆县| 百家乐娱乐平台代理佣金| 金木棉百家乐官网网络破解| 百家乐平一直压庄| 芝加哥百家乐官网的玩法技巧和规则 | 澳门百家乐投注法| 百家乐官网兑换棋牌| 棋牌室| 百家乐送錢平臺| 皇冠正网开户| 百家乐开户优惠多的平台是哪家| 定做百家乐官网桌子| 普陀区| 百家乐赢退输进有哪些| 百家乐视频大厅| 百家乐官网娱乐城信息| 德州扑克中文单机版| 百家乐推荐| 百家乐菲律宾| 大家赢百家乐投注| 泰无聊棋牌游戏中心| 免水百家乐的玩法技巧和规则| 澳门百家乐官网备用网址| 综艺| 乐百家娱乐| 皇家百家乐的玩法技巧和规则| 中原百家乐官网的玩法技巧和规则| 澳门盘口| 威尼斯人娱乐城是骗子| 宝格丽百家乐官网娱乐城| 白金国际| 乐九娱乐| e世博线上娱乐| 星期八娱乐| 轮台县| bet365体育投注| A8娱乐城|