国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 淺析Java虛擬機詳解之概述、對象生存法則

淺析Java虛擬機詳解之概述、對象生存法則

2021-09-01 10:23小游子YKY Java教程

這篇文章主要介紹了Java虛擬機詳解之概述、對象生存法則,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

Java與C++之間有一堵由內存分配和垃圾收集技術所圍成的高墻,墻外面的人想進去,墻里面的人卻想出來。

淺析Java虛擬機詳解之概述、對象生存法則

一、概述

Java堆和方法區這兩個區域有著很顯著的不確定性:

1、一個接口的多個實現類需要的內存可能會不一樣,一個方法所執行的不同條件分支所需要的內存也可能不一樣
2、只有處于運行期間,我們才能知道程序究竟會創建哪些對象,創建多少個對象,這部分內存的分配和回收是動態的

垃圾收集器所關注的正是這部分的內存該如何管理

淺析Java虛擬機詳解之概述、對象生存法則

二、對象已死?

1、引用計數法

在對象中添加一個引用計數器,每當有一個地方引用它時,計數器就加一;當引用失效時,計數器就減一;任何時刻計數器為零的對象是不可能再被使用的。

引用計數器雖然占用了一些額外的內存空間來進行計數,原理簡單,判定效率很高;

為什么主流Java虛擬機沒有使用引用計數器來管理內存呢

引用計數法看似簡單的算法有很多例外情況要考慮,必須配合大量額外處理才能保證正確的工作,比如單純的引用計數很難解決對象之間互相循環引用的問題

引用計數器的缺陷

  1. /**
  2. * @Author: yky
  3. * @CreateTime: 2020-12-13
  4. * @Description: 引用計數器的缺陷
  5. */
  6. public class ReferenceCountingGC {
  7. public Object instance = null;
  8. private static final int _1MB = 1024 * 1024;
  9. /**
  10. * 這個成員變量唯一作用是占內存
  11. */
  12. private byte[] bigSize = new byte[2 * _1MB];
  13. public static void testGC(){
  14. ReferenceCountingGC objA = new ReferenceCountingGC();
  15. ReferenceCountingGC objB = new ReferenceCountingGC();
  16. objA.instance = objB;
  17. objB.instance = objA;
  18. //發生GC,objA、objB能否被回收
  19. System.gc();
  20. }
  21. }

運行代碼收查看日志信息發現,這兩個對象均被回收虛擬機并沒有因為這兩個相互引用就放棄回收他們---->Java虛擬機并不是通過計數算法來判斷對象是否存活的;

2、可達性分析算法

該算法的核心思想:通過一系列稱為“GC Roots”的根對象作為起始節點集,從這些結點開始,根據引用關系向下搜索,搜索過程所走過的路徑稱為“引用鏈”,如果某個對象到GC Roots間沒有任何引用鏈相連(圖論話來說從GC Roots到這個對象不可達時,則證明此對象是不可能再被使用的)

淺析Java虛擬機詳解之概述、對象生存法則

對象obj5obj6obj7雖然有關聯,但是他們到GC roots不可達因此他們會被判定為可回收對象

在 Java 語言中,可作為 GC Roots 的對象包括以下幾種

  • 虛擬機棧(棧中的本地變量表)中的引用對象,如各線程被調用的方法堆棧中使用到的參數、局部變量、臨時變量等;
  • 方法區中的類靜態屬性引用的對象,如Java類的引用類型靜態變量;
  • 方法區中的常量引用的對象,如字符串常量里的引用;
  • 本地方法棧總JNI(Navicat方法)引用的對象;
  • Java虛擬機內部的引用
  • 所有被同步鎖(synchronized關鍵字)持有的對象
  • 反應Java虛擬機內部情況的JMXBean、JVMTI中注冊的回調、本地代碼緩存等;
  • 根據用戶所選的垃圾收集器以及當前回收的內存區域不同,還可以有其他對象“臨時性”地加入;

無論通過哪種算法判斷對象是否存活都和“引用”離不開關系。

1)強引用

是指在程序代碼之間普遍存在的引用賦值,Object obj = new Object();這種引用關系。
無論什么情況下,只要強引用關系還在,垃圾收集器就不會回收掉被引用的對象;

2)軟引用

用來描述一些還有用,但非必須的對象。只要軟引用關聯著的對象,在系統將要發生內存溢出前,會把這些對象列進回收范圍之中進行第二次回收;如果這次的回收還沒有足夠的空間,才會拋出內存溢出的異常;

JDK1.2后提供SoftReference類實現軟引用:

Soft reference objects, which are cleared at the discretion of the garbage
collector in response to memory demand. Soft references are most often used
to implement memory-sensitive caches.

3)弱引用

弱引用也被用來描那些非必須對象,強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發生為止,當垃圾收集器開始工作,無論當前內存是足夠,都會回收掉只被弱引用關聯的對象;

JDK1.2后WeakReference類用來實現弱引用:

Weak reference objects, which do not prevent their referents from being

made finalizable, finalized, and then reclaimed. Weak references are most

often used to implement canonicalizing mappings.

4)虛引用

也叫“幽靈引用”、“幻影引用”,最弱的一種引用關系

  • 一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用獲得一個對象的實例;
  • 為一個對象設置虛引用的唯一目的是為了能在這個對象被收集器回收時收到一個系統通知;

PhantomReference類來實現虛引用:

Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed. Phantom references are most often used to schedule post-mortem cleanup actions.

應用需要讀取大量本地圖片

如果每次讀取圖片都從硬盤讀取,則會嚴重影響性能;解決方案:【軟引用或者弱引用】

  1. Map<String,SoftReference<BitMap>> imp = new HashMap<String,SoftReference<BitMap>>

4、生存還是死亡?

在進行過可達性分析后的對象也不一定是非死不可的,該對象進行可達性分析后,發現沒有與GC Roots相連接的引用鏈

  • 這個對象就會第一次被標記起來;對對象是否必要執行finalize()方法進行判斷(已經被虛擬機調用過finalize()方法或者沒有覆蓋finalize()方法都認為是沒有必要執行該finalize()方法)
  • F-Queue隊列中存放該對象,優先級較低的Finalizer線程會去執行它;Gc 會對這個隊列里面的對象再進行一次標記,如果在finalize方法中,對象沒有自己自救的話,它就會被標記回收
  • finalize方法自救自己的辦法是:重新與引用鏈上面的任何一個對象建立連接;如把自己this賦值給某個類或對象的成員變量
  1. /**
  2. 1.對象可以在GC時自救
  3. 2.自救的辦法只有一次,因為一個finalize方法最多只能被調用一次
  4. **/
  5. public class FinalizeEscapeGC {
  6.  
  7. public static FinalizeEscapeGC SAVE_HOOK = null;
  8. public void isAlive(){
  9. System.out.println("yes,I am still alive :)");
  10. }
  11.  
  12. @Override
  13. protected void finalize() throws Throwable {
  14. super.finalize();
  15. System.out.println("finalize method executed !");
  16. FinalizeEscapeGC.SAVE_HOOK = this;
  17. }
  18.  
  19. public static void main(String [] args) throws InterruptedException {
  20. SAVE_HOOK = new FinalizeEscapeGC();
  21. //對象第一次成功拯救自己
  22. SAVE_HOOK = null;
  23. System.gc();
  24. //因為finalize優先級很低,所以延遲0.5s以等待它;
  25. Thread.sleep(500);
  26. if(SAVE_HOOK != null){
  27. SAVE_HOOK.isAlive();
  28. }else{
  29. System.out.println("no, i am dead :(");
  30. }
  31.  
  32. //下面這段代碼再執行一遍,驗證對象是不是可以成功
  33. SAVE_HOOK = null;
  34. System.gc();
  35. Thread.sleep(500);
  36. if(SAVE_HOOK != null){
  37. SAVE_HOOK.isAlive();
  38. }else{
  39. System.out.println("no, i am dead :(");
  40. }
  41. }
  42.  
  43. }

結果如下:

finalize method executed !
yes,I am still alive :)
no, i am dead :(

  • 并不鼓勵使用這種辦法來拯救對象,它的運行代價高昂,不確定性大,無法保證順序;
  • finalize方法能做的所有工作,try-finally也可以做的更好,更及時,所以希望忘記這個方法的存在;

5、回收方法區

很多人認為方法區(或者HotSpot虛擬機中的元空間或永久代)是沒有垃圾收集行為的,《Java虛擬機規范》中確實說過可以不要求虛擬機在方法區實現垃圾收集,而且在方法區進行垃圾收集的“性價比”一般比較低:在堆中,尤其是在新生代中,常規應用進行一次垃圾收集一般可以回收70%~95%的空間,而永久代的垃圾收集效率遠低于此。

方法區的垃圾收集主要回收兩部分:廢棄的常量和不再使用的類型;

  • 回收廢棄常量與回收Java堆中的對象非常類似。以常量池中字面量的回收為例:

假如一個字符串“Java”已經進入了常量池中,但是當前系統沒有任何一個字符串對象的值是“Java”,換句話說是沒有任何String對象引用常量池中的“Java”常量,也沒有其他地方引用了這個字面量,如果在這時候發生內存回收,而且必要的話,這個“Java”常量就會被系統清理出常量池。

  • 常量池中的其他類(接口)、方法、字段的符號引用也與此類似。

判定一個常量是否是“廢棄常量”比較簡單。而要判定一個類是否是“無用的類”的條件則相對苛刻許多。類需要同時滿足下面3個條件才能算是“無用的類”:

  1. 該類所有的實例都已經被回收,也就是Java堆中不存在該類的任何實例。
  2. 加載該類的ClassLoader已經被回收。
  3. 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

虛擬機可以對滿足上述3個條件的無用類進行回收,這里說的僅僅是“被允許”,而不是和對象一樣,不使用了就必然會回收。在大量使用反射、動態代理、CGLib等bytecode框架的場景,以及動態生成JSP和OSGi這類頻繁自定義ClassLoader的場景都需要虛擬機具備類卸載的功能,以保證不會被方法區造成過大的內存壓力。

到此這篇關于Java虛擬機詳解之概述、對象生存法則的文章就介紹到這了,更多相關Java虛擬機內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://youkaiyang.blog.csdn.net/article/details/115347506

延伸 · 閱讀

精彩推薦
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7472021-02-04
主站蜘蛛池模板: 天天插狠狠插 | 国产精品免费一区二区 | 日韩欧美一二三区 | 久久精品国产99 | 含羞草www国产在线视频 | 成人黄色av | 亚洲一区视频 | 麻豆.蜜桃.91.天美入口 | 久久久久久亚洲 | 精品国产一区二区三区在线观看 | 亚洲一区二区三区视频 | 国产成人无遮挡在线视频 | 国产成人一区二区三区 | 免费看黄色小视频 | 国产精品一区二区无线 | 福利久久| 日韩和的一区二在线 | 久久99精品一区二区三区 | 日韩国产在线 | 中文精品久久 | 欧美日韩高清在线一区 | 国产精品免费观看 | 国产黄色成人 | 亚州ava | 久久久国产精品视频 | 中文字幕一二三区 | 国产亚洲精品美女久久久久久久久久 | 欧美成人a∨高清免费观看 亚洲国产精品尤物yw在线观看 | 久久婷婷欧美 | 国产精品美女久久久久久免费 | 亚洲欧美日韩精品久久奇米色影视 | 久久久久久网站 | 求av网址| 亚洲精品久久久一区二区三区 | 欧美第5页 | 精品视频一区二区 | 国产成人黄色网址 | 在线观看一区二区三区视频 | 亚洲91精品 | 国产黄色一级大片 | 日本精品视频在线观看 |