最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網 會員登陸 & 注冊

Java虛擬機

2021-05-07 08:56 作者:光耀三十洲  | 我要投稿

一、Java虛擬機發(fā)展史

  1. Sun Classic/Exact VM

  2. Sun Hotspot VM

  3. 移動端虛擬機KVM/Squawk VM/JavaInJava

  4. BEA JRockit/IBM J9VM

  5. 其他:Apache Harmony/Google Android Dalvik/Microsoft VM

Sun Classic VM:世界第一款商用Java虛擬機,純解釋方式來執(zhí)行Java代碼,如果要使用JIT編譯器,必須外掛。技術比較原始,使命已經終結。JDK1.0

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

Sun Exact VM:已經具備現(xiàn)代高性能虛擬機的雛形,編譯器和解釋器混合工作模式。準確式GC,虛擬機可以知道內存中的某個位置的數(shù)據(jù)具體是什么類型。JDK1.2

Sun Hotspot VM:目前使用最廣泛的JVM。熱點代碼探測技術:通過執(zhí)行計數(shù)器找出最具編譯價值的代碼,然后通知JIT編譯器以方法為單位進行編譯。JDK1.3成為默認虛擬機

KVM,CDC/CLDC Hotspot Implenmentation,Squawk VM,JavaInJava,Maxine VM。

JRockit:號稱世界上最快的Java 虛擬機。2008、2009年Oracle分別收購BEA和Sun,整合兩款VM,在HotSpot的基礎上,移植JRockit的優(yōu)秀特征,比如JRockit的垃圾回收器和MissonControl服務套件

Apache Harmony/Google Android Dalvik/Microsoft VM平臺專有

二、Java虛擬機運行時數(shù)據(jù)區(qū)

程序計數(shù)器:表示的是當前線程所執(zhí)行的字節(jié)碼的行號指示器,解釋器通過改變這個計數(shù)器來選取下一條需要執(zhí)行的字節(jié)碼指令。程序計數(shù)器是在Java虛擬機規(guī)范中唯一沒有規(guī)定任何OutOfMemoryError異常情況的區(qū)域。

虛擬機棧:描述的是Java方法執(zhí)行的內存模型,每個方法在執(zhí)行時都會創(chuàng)建一個棧幀,用于存儲局部變量表、操作數(shù)棧、方法出口等信息。平時說的堆、棧中的棧。如果線程請求的深度大于虛擬機所允許的深度,將拋出StackOverflowError異常。如果虛擬機棧動態(tài)擴展,而擴展時無法申請到足夠的內存,就會拋出OutOfMemoryError異常。

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

本地方法棧:與虛擬機棧發(fā)揮的作用是非常相似的,虛擬機棧為Java方法服務,本地方法棧為Native方法服務。

Java堆:被所有線程共享,是Java虛擬機所管理的內存中最大的一塊。Java堆唯一的目的是存放對象實例,幾乎所有的對象實例都在這里分配內存。Java堆是垃圾收集器管理的主要區(qū)域,又被稱為GC堆,可細分為新生代和老年代,Eden空間:From Survivor空間:To Survivor空間。當堆無法滿足內存分配需求時,將拋出OutOfMemoryError異常。

方法區(qū):用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量等,也稱“永久代”。這個區(qū)域的內存回收目標主要是針對常量池的回收和對類型的卸載。運行時常量池:存放編譯器生成的各種字面量和符號引用。當方法區(qū)無法滿足內存分配需求時,將拋出OutOfMemoryError異常。

三、垃圾收集

垃圾收集,主要就是思考GC需要完成的3件事情:

1. Which:哪些資源要回收

對象已死嗎?如何判定一個對象是否可以回收?主要有兩種方法:1.引用計數(shù)算法2.可達性分析算法 引用計數(shù)法:在對象中添加一個引用計數(shù)器,每當有一個地方引用它時,計數(shù)器就加1;當引用失效時,計數(shù)器減1;其中計數(shù)器為0的對象是不可能再被使用的已死對象。當兩個對象相互引用時,這兩個對象就不會被回收。引用計數(shù)算法不被主流虛擬機采用,主要原因是它很難解決對象之間相互循環(huán)引用的問題。

可達性分析算法:通過一系列的稱為GC Roots的對象作為起始點,從這些節(jié)點開始向下搜索,搜索所經過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連(對象不可達)時,這個對象就是不可用的。

2.When:什么時候回收?

要真正宣告一個對象死亡,至少要經歷兩次標記過程: 若對象在進行可達性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈,會被 第一次標記 并且進行一次篩選。篩選的條件是此對象是否有必要執(zhí)行finalize()方法(如當對象沒有重寫finalize()方法或者finalize()方法已經被虛擬機調用過則認為沒有必要執(zhí)行)。 如果有必要執(zhí)行則將該對象放置在F-Queue隊列中,并在稍后由一個由虛擬機自己建立的、低優(yōu)先級的Finalizer線程去執(zhí)行它;稍后GC將對F-Queue中的對象進行第二次標記,如果對象還是沒有被引用,則會被回收。

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

3. How:如何回收?

主要的垃圾收集算法: 1)標記-清除算法 (Mark-Sweep)

標記:首先標記所有需要回收的對象

清除:在標記完成后統(tǒng)一回收所有被標記的對象

缺點 效率問題,標記和清除兩個過程的效率都不高(回收后空間碎片過多,再次回收(即可達性分析時)有時需要遍歷整個內存區(qū)域)。

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

空間問題,標記清除之后會產生大量不連續(xù)的內存碎片,空間碎片太多可能會導致以后在程序運行過程中需要分配較大對象時,無法找到足夠的連續(xù)內存,而不得不提前觸發(fā)另一次垃圾收集動作。

2)復制算法(Copying)

思路:將可用內存按容量分為兩個塊,每次只用其中之一。當這一塊內存用完之后,將還存活的對象復制到另一邊去,然后清除所有已經使用過的部分。

優(yōu)點每次都是對整個半區(qū)進行內存回收,內存分配時也就不用考慮內存碎片等復雜情況,只要移動堆頂指針,按順序分配內存即可,實現(xiàn)簡單,運行高效。

缺點代價是將內存縮小為了原來的一半,未免太高了一點。

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

解決方法新生代中的對象98%是“朝生夕死”的,所以并不需要按照1:1的比例來劃分內存空間,而是將內存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。 在HotSpot里,考慮到大部分對象存活時間很短將內存分為Eden和兩塊Survivor,默認比例為8:1:1。代價是存在部分內存空間浪費,適合在新生代使用。

3)標記-整理算法(Mark-Compact)

標記過程仍然與“標記-清除”算法一樣,但后續(xù)步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。

4)分代收集算法 當前商用虛擬機都采用了這種算法,根據(jù)對象的存活周期將內存劃分為幾塊,一般是把Java堆分為新生代和老生代,根據(jù)各個年代采用適當?shù)氖占惴ā?/p>

新生代一般采用復制算法(Copying)。老生代一搬采用 標記-清理(Mark-Sweep) 或者標記-整理(Mark-Compact) 進行回收。

四、Android常見的內存泄漏

1、Handler 引起的內存泄漏

在Android開發(fā)中,我們經常會使用Handler來控制主線程UI程序的界面變化,使用非常簡單方便,但是稍不注意,很容易引發(fā)內存泄漏。

我們知道,Handler、Message、MessageQueue是相互關聯(lián)在一起的,Handler通過發(fā)送消息Message與主線程進行交互,如果Handler發(fā)送的消息Message尚未被處理,該Message及發(fā)送它的Handler對象將被MessageQueue一直持有,這樣就可能會導致Handler無法被回收。SecondActivity代碼中有一個延遲1秒執(zhí)行的消息Message,當界面從SecondActivity跳轉到ThirdActivity時,SecondActivity自動進入后臺,此時如果系統(tǒng)資源緊張(或者打開設置里面的“不保留活動”選項),SecondActivity將會被finish。但問題來了,由于SecondActivity的Handler對象mHandler為非靜態(tài)匿名內部類對象,它會自動持有外部類SecondActivity的引用,從而導致SecondActivity無法被回收,造成內存泄漏

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF


解決辦法:將Handler聲明為靜態(tài)內部類,就不會持有外部類SecondActivity的引用,其生命周期就和外部類無關,如果Handler里面需要context的話,可以通過弱引用方式引用外部類。

通過上面的方法,創(chuàng)建一個靜態(tài)Handler內部類,其持有的對象context使用弱引用,可以避免SecondActivity內存泄漏,但是Looper線程的消息隊列中可能還有待處理的消息,所以在Activity的onDestroy方法中,還要記住移除消息隊列中待處理的消息

2、單例模式引起的內存泄漏

由于單例的生命周期是和app的生命周期一致的,如果使用不當很容易引發(fā)內存泄漏。

這是一個單例模式的標準寫法,表面上看沒有任何問題,但是細心的同學會發(fā)現(xiàn),構建該單例的一個實例時需要傳入一個Context,此時傳入的Context就非常關鍵,如果此時傳入的是Activity,由于Context會被創(chuàng)建的實例一直持有,當Activity進入后臺或者開啟設置里面的不保留活動時,Activity會被銷毀,但是單例持有它的Context引用,Activity又沒法銷毀,導致了內存泄漏

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

上述代碼中,SecondActivity2包含一個內部類InnerClass,并且在onCreate代碼中創(chuàng)建了InnerClass的靜態(tài)實例mInner,該實例和app的生命周期是一致的。

在某些場景,如Activity需要頻繁切換,需要不斷加載大量圖片的場合,是會出現(xiàn)上述代碼的,每次Activity啟動之后都會使用該單例,避免重復一些有壓力的操作。但是這樣會引起內存泄漏,因為非靜態(tài)的內部類InnerClass會自動持有外部類SecondActivity2的引用,創(chuàng)建的靜態(tài)實例mInner就會一直持有SecondActivity2的引用,導致SecondActivity2需要銷毀的時候沒法正常銷毀。

上述代碼的正確做法是把內部類InnerClass修改為靜態(tài)的就可以避免內存泄漏了,因為靜態(tài)內部類InnerClass不在持有外部類SecondActivity2的引用了。

當然,也可以把InnerClass單獨抽出來作為一個類,寫成單例模式,完成同樣的功能,同時也可以避免內存泄漏。

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF

3、非靜態(tài)內部類創(chuàng)建靜態(tài)實例引起的內存泄漏

上述代碼中,SecondActivity2包含一個內部類InnerClass,并且在onCreate代碼中創(chuàng)建了InnerClass的靜態(tài)實例mInner,該實例和app的生命周期是一致的。

在某些場景,如Activity需要頻繁切換,需要不斷加載大量圖片的場合,是會出現(xiàn)上述代碼的,每次Activity啟動之后都會使用該單例,避免重復一些有壓力的操作。但是這樣會引起內存泄漏,因為非靜態(tài)的內部類InnerClass會自動持有外部類SecondActivity2的引用,創(chuàng)建的靜態(tài)實例mInner就會一直持有SecondActivity2的引用,導致SecondActivity2需要銷毀的時候沒法正常銷毀。

上述代碼的正確做法是把內部類InnerClass修改為靜態(tài)的就可以避免內存泄漏了,因為靜態(tài)內部類InnerClass不在持有外部類SecondActivity2的引用了。

當然,也可以把InnerClass單獨抽出來作為一個類,寫成單例模式,完成同樣的功能,同時也可以避免內存泄漏。

4、監(jiān)聽器(各種需要注冊的Listener,Watcher等)

5、資源對象沒關閉造成內存泄漏

6、屬性動畫

監(jiān)聽器、資源對象、以及動畫,要及時的關閉,避免造成內存泄漏

學習更多,請點擊:https://www.bilibili.com/video/BV1nB4y1w7BT

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1tZ4y1F7eK

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV135411w7Jg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7fm

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??https://www.bilibili.com/video/BV1sf4y1p7mF


作者:自如大前端團隊
鏈接:https://juejin.cn/post/6959082139400798215
來源:掘金
著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處。


Java虛擬機的評論 (共 條)

分享到微博請遵守國家法律
临泽县| 泸定县| 商河县| 虎林市| 清水河县| 承德县| 钦州市| 九寨沟县| 汉沽区| 乐亭县| 靖州| 新竹县| 东乌| 泾阳县| 武定县| 德阳市| 布拖县| 湘潭市| 安福县| 阳春市| 湖州市| 和田县| 武鸣县| 杭锦后旗| 甘德县| 万山特区| 沾化县| 原平市| 江油市| 天门市| 和静县| 营山县| 永修县| 柘城县| 保定市| 通许县| 铜川市| 淮安市| 丹棱县| 哈尔滨市| 崇州市|