一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Android內(nèi)存泄漏問題如何優(yōu)化?

工程師 ? 來源:CSDN博客 ? 作者:CSDN博客 ? 2020-09-11 15:55 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

作者:無名之輩FTER

來源:CSDN博客

眾所周知,Java因其擁有獨(dú)特的虛擬機(jī)(JVM)設(shè)計(jì),使其成為一門跨平臺(tái)、內(nèi)存自動(dòng)管理的高級(jí)開發(fā)語言。所謂跨平臺(tái),即“一次編譯,多次運(yùn)行”,從而解決了不同平臺(tái)由于編譯器不同導(dǎo)致無法運(yùn)行問題;所謂內(nèi)存自動(dòng)管理,即Java不像C/C++那樣需要開發(fā)者來分配、釋放內(nèi)存,它擁有一套垃圾回收機(jī)制來管理內(nèi)存,這套機(jī)制減輕了很多潛在的內(nèi)存回收不當(dāng)問題。然而,雖然Java的垃圾回收機(jī)制非常優(yōu)秀,但當(dāng)我們?cè)趯懗绦蜻^程中有一些不好的習(xí)慣可能會(huì)導(dǎo)致部分內(nèi)存無法被垃圾回收器回收,而我們自己又無法進(jìn)行回收,從而導(dǎo)致這部分內(nèi)存長(zhǎng)期被占用無法釋放,并且隨著這部分內(nèi)存的增大,極大的影響了程序的性能,這種情況被稱之為“內(nèi)存泄漏”。

01

Java虛擬機(jī)(JVM)

虛擬機(jī)是一種虛構(gòu)出來的抽象化計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的,它擁有自己完善的虛擬硬件架構(gòu),如處理器、堆棧、寄存器等,而且還具有相應(yīng)的指令系統(tǒng)。Java虛擬機(jī)就是這么一種虛擬機(jī)。Java虛擬機(jī),即Java Virtual Machine(JVM),是運(yùn)行所有Java程序的抽象計(jì)算機(jī),是Java語言的運(yùn)行環(huán)境,它屏蔽了與具體操作系統(tǒng)平臺(tái)相關(guān)的信息,使得Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼)。任何平臺(tái)只要裝有針對(duì)于該平臺(tái)的Java虛擬機(jī),字節(jié)碼文件(.class)就可以在該平臺(tái)上運(yùn)行,即“一次編譯,多次運(yùn)行”,正是因?yàn)槿绱耍瑥亩沟肑ava語言具有跨平臺(tái)移植的特性。

Java虛擬機(jī)本質(zhì)上就是一個(gè)程序,Java程序的運(yùn)行依靠具體的Java虛擬機(jī)實(shí)例,每個(gè)Java應(yīng)用程序都對(duì)應(yīng)著一個(gè)Java虛擬機(jī)實(shí)例,且Java程序與其對(duì)應(yīng)Java虛擬機(jī)實(shí)例生命周期一致。在Java虛擬機(jī)規(guī)范中,JVM主要包括五大模塊,即類裝載器子系統(tǒng)、運(yùn)行時(shí)數(shù)據(jù)區(qū)、執(zhí)行引擎、本地方法接口和垃圾收集模塊。其中,類加載器子系統(tǒng),用于加載字節(jié)碼文件到內(nèi)存,就是JVM中的runtime data area(運(yùn)行時(shí)數(shù)據(jù)區(qū))的method area方法區(qū),整個(gè)過程中裝載器只負(fù)責(zé)文件結(jié)構(gòu)格式能夠被裝入,并不負(fù)責(zé)能不能運(yùn)行;運(yùn)行時(shí)存儲(chǔ)區(qū),即JVM內(nèi)存區(qū)域,JVM運(yùn)行程序的時(shí)候使用;執(zhí)行引擎,在不同的虛擬機(jī)實(shí)現(xiàn)里面,執(zhí)行執(zhí)行引擎可能會(huì)有解釋器解釋執(zhí)行字節(jié)碼文件或即時(shí)編譯器編譯產(chǎn)生本地代碼執(zhí)行字節(jié)碼文件,可能兩種都有;本地方法接口,即Java Native Interface(JNI),用于與本地庫(native library)交互,是Java與其他編程語言(C/C++)交互的“橋梁”;垃圾收集,用于對(duì)已分配的內(nèi)存資源進(jìn)行回收,主要是Java堆和方法區(qū)的內(nèi)存。JVM架構(gòu)如下圖所示:

1.1 JVM內(nèi)存管理

Java虛擬機(jī)在執(zhí)行Java程序時(shí)會(huì)把它所管理的內(nèi)存劃分若干個(gè)不同的數(shù)據(jù)區(qū)域,這些區(qū)域的用途各不相同,創(chuàng)建、銷毀的時(shí)間也各有區(qū)別,比如有的隨著Java虛擬機(jī)進(jìn)程的啟動(dòng)而存在、有的區(qū)域則依賴于用戶線程的啟動(dòng)和結(jié)束而創(chuàng)建、銷毀,但它們有一個(gè)共同的“名字”,即運(yùn)行時(shí)數(shù)據(jù)區(qū)域。Java虛擬機(jī)管理的內(nèi)存主要有:程序計(jì)數(shù)器、Java虛擬機(jī)棧、本地方法棧、Java堆、方法區(qū)以及直接內(nèi)存等,其中,程序計(jì)數(shù)器、虛擬機(jī)棧和本地方法棧為線程私有,方法區(qū)和Java堆為線程間共享。

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

程序計(jì)數(shù)器(Program Counter Register)是內(nèi)存中的一塊較小的區(qū)域,它可以看作成是 當(dāng)前線程 所執(zhí)行的字節(jié)碼行號(hào)指示器,依賴于 用戶線程 的啟動(dòng)和結(jié)束而創(chuàng)建、銷毀,是 線程私有 內(nèi)存數(shù)據(jù)區(qū)域。由于Java虛擬機(jī)的多線程是通過線程輪流切換并分配處理器執(zhí)行時(shí)間的方式來實(shí)現(xiàn)的,在任何一確定的時(shí)刻,一個(gè)處理器都只會(huì)執(zhí)行一條線程中的指令,因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,各個(gè)線程之間計(jì)數(shù)器互不影響、獨(dú)立存儲(chǔ)。需要注意的是,如果線程正在執(zhí)行的是一個(gè) Java方法 ,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果線程正在執(zhí)行的是 Native方法 ,那么這個(gè)計(jì)數(shù)器的值為空。

在Java虛擬機(jī)規(guī)范中,程序計(jì)數(shù)器是唯一一個(gè)沒有規(guī)定任何 OutOfMemoryError 情況的區(qū)域。

Java虛擬機(jī)棧

類似于程序計(jì)數(shù)器,Java虛擬機(jī)棧(Java Virtual Machine Stacks)也是 線程私有 ,生命周期與用戶線程周期相同,它描述的是Java方法執(zhí)行的內(nèi)存模型,即 每個(gè)Java方法 在執(zhí)行時(shí)JVM會(huì)為其在這部分內(nèi)存中創(chuàng)建一個(gè) 棧幀(Stack Frame) 用于存儲(chǔ) 局部變量表 、 操作數(shù)棧 、 動(dòng)態(tài)鏈接 以及 方法出口信息 等,每一個(gè)方法從調(diào)用到執(zhí)行完成的過程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧和出棧過程。局部變量表是我們?cè)陂_發(fā)過程中接觸較多的部分,它存放了 編譯器可知 的各種 基本數(shù)據(jù)類型(byte/boolean/char/int/short/long/float/double) 、 對(duì)象引用(reference類型) 和 returnAddress類型 ,其中,64位長(zhǎng)度的long和double類型的數(shù)據(jù)占用2個(gè)局部變量空間,其他的類型占1個(gè)( 4個(gè)字節(jié) )。局部變量表所需的內(nèi)存空間在 編譯期 間完成分配,當(dāng)進(jìn)入一個(gè)方法時(shí),這個(gè)方法需要在幀中分配多大的局部變量空間是完成確定的,在方法 運(yùn)行期間不會(huì)改變局部變量表的大小 。下圖是虛擬機(jī)棧存儲(chǔ)示意圖:

在Java虛擬機(jī)規(guī)范中,虛擬機(jī)??赡軙?huì)出現(xiàn)兩種異常情況,即 StackOverflowError 和 OufOfMemoryError ,其中,StackOverflowError出現(xiàn)在 如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度 ;OufOfMemoryError出現(xiàn)在 如果虛擬機(jī)??梢詣?dòng)態(tài)擴(kuò)展,但是擴(kuò)展后仍然無法申請(qǐng)到足夠的內(nèi)存 。

本地方法棧

本地方法棧(Native Method Stack)與虛擬機(jī)棧所發(fā)揮的作用非常相似,它們之間的區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(即 字節(jié)碼 ),而本地方法棧則為虛擬機(jī)使用到的 Native方法 服務(wù)。下圖演示了一個(gè)線程調(diào)用Java方法和本地方法時(shí)的棧,以及虛擬機(jī)棧和本地方法棧之間毫無障礙的跳轉(zhuǎn)。示意圖如下:

在Java虛擬機(jī)規(guī)范中,本地方法棧也會(huì)出現(xiàn) StackOverflowError 和 OufOfMemoryError 異常情況。

Java堆

Java堆(Java Heap)是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊,它在 JVM啟動(dòng) 時(shí)被創(chuàng)建,生命周期與JVM相同,是被所有 線程所共享 的一塊區(qū)域,此區(qū)域唯一的目的是存放 對(duì)象實(shí)例 和 數(shù)組 ,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。Java堆是垃圾收集器管理的主要區(qū)域,也是“ 內(nèi)存泄漏 ”集中出現(xiàn)的地方。由于JVM中的垃圾收集器大部分采用分代收集算法,因此,Java堆又被細(xì)分為:新生代和老年代,其中, 新生代 區(qū)域存放創(chuàng)建不久的對(duì)象, 老年代 存放經(jīng)歷過多次GC后仍然存活的對(duì)象。實(shí)際上,根據(jù)JVM規(guī)范,Java堆還可被繼續(xù)細(xì)分為 Eden 空間、 From Survivor空間 以及 To Survivor空間 等,這個(gè)我們?cè)诶厥諜C(jī)制模塊詳細(xì)闡述。下圖是Java堆內(nèi)存劃分示意圖:

在JVM規(guī)范中,如果堆可以動(dòng)態(tài)擴(kuò)展,但是擴(kuò)展后仍然無法申請(qǐng)到足夠的內(nèi)存,就會(huì)拋出OutOfMemoryError異常。當(dāng)然,我們可以通過 -Xmx 和 -Xms 來控制堆內(nèi)存的大小,其中, -Xmx 用于設(shè)置Java堆起始的大小, -Xms 用于設(shè)置Java堆可擴(kuò)展到最大值。

方法區(qū)

像Java堆一樣,方法區(qū)(Method Area)是各個(gè) 線程共享 的內(nèi)存區(qū)域,它的生命周期與虛擬機(jī)相同,即隨著虛擬機(jī)的啟動(dòng)和結(jié)束而創(chuàng)建、銷毀。方法主要用于存放 已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量以及即時(shí)編譯器(JIT)編譯后的代碼 等數(shù)據(jù),它的大小決定了系統(tǒng)能夠加載多少個(gè)類,如果定義的類太多,導(dǎo)致方法區(qū)拋出OutOfMemoryError異常。需要注意的是,對(duì)于JDK1.7來說,在HotSpot虛擬機(jī)中方法區(qū)可被理解為“永久區(qū)”,但是JDK1.8以后,方法區(qū)已被取消,替代的是 元數(shù)據(jù)區(qū) 。元數(shù)據(jù)區(qū)是一塊堆外的直接內(nèi)存,與永久區(qū)不同,如果不指定大小,默認(rèn)情況下在類加載時(shí)虛擬機(jī)會(huì)盡可能加載更多的類,直至系統(tǒng)內(nèi)存被消耗殆盡。當(dāng)然,我們可以使用參數(shù) -XX:MaxMetaspaceSzie 來指定元數(shù)據(jù)區(qū)的大小。

運(yùn)行時(shí)常量池用于存放編譯期生成的各種字面量和符號(hào)引用。

直接內(nèi)存

直接內(nèi)存(Direct Memory)不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是Java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域,它是在JDK1.4中新加入的NIO(New Input/Output)類,通過引入了一種基于通道與緩沖區(qū)的I/O方式,使用Native函數(shù)庫直接分配得到的堆外內(nèi)存。對(duì)于這部分內(nèi)存區(qū)域,主要通過存儲(chǔ)在Java堆中的 DirectByteBuffer 對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作,直接內(nèi)存的存在避免了在Java堆和Native堆中來回復(fù)制數(shù)據(jù),從而在某些場(chǎng)景能夠顯著地提高性能。

本機(jī)直接內(nèi)存的分配不會(huì)受到Java堆大小的限制,但是仍然會(huì)受到本機(jī)總內(nèi)存( 包括RAM以及SWAP或者分頁文件 )大小以及處理器尋址空間的限制。如果申請(qǐng)分配的內(nèi)存總和(包括直接內(nèi)存)超過了物理內(nèi)存的限制,就會(huì)導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn)OutOfMemoryError異常。

1.2 垃圾回收器與內(nèi)存分配策略

在上一節(jié)中我們?cè)敿?xì)分析了JVM的運(yùn)行時(shí)內(nèi)存區(qū)域,了解到程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧是線程的私有區(qū)域,當(dāng)線程結(jié)束時(shí)這部分所占內(nèi)存資源將會(huì)自動(dòng)釋放,而線程的共享區(qū)域 Java堆 是存放所有對(duì)象實(shí)體的地方,因此是垃圾回收器回收( GC,Garbage Collection )的主要區(qū)域。(方法區(qū)也會(huì)有GC,但是一般我們討論的是Java堆)

1.2.1 如何判斷對(duì)象“已死”?

垃圾收集器在回收一個(gè)對(duì)象,第一件事就是確定這些對(duì)象之中有哪些是“存活”的,哪些已經(jīng)“死亡”,而垃圾回收器回收的就是那些已經(jīng)“死亡”的對(duì)象。如何確定對(duì)象是否已經(jīng)死亡呢?通常,我們可能會(huì)說當(dāng)一個(gè)對(duì)象沒被任何地方引用時(shí),就認(rèn)為該對(duì)象已死。但是,這種表述貌似不夠準(zhǔn)確,因此,JVM規(guī)范中給出了兩種判斷對(duì)象是否死亡的方法,即 引用計(jì)數(shù)法 和 可達(dá)性分析 。

引用計(jì)數(shù)法

引用計(jì)數(shù)法實(shí)現(xiàn)比較簡(jiǎn)單,它的實(shí)現(xiàn)原理: 給對(duì)象一個(gè)引用計(jì)數(shù)器,每當(dāng)一個(gè)地方引用它時(shí),計(jì)數(shù)器就加1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就會(huì)被認(rèn)為已經(jīng)死亡 。客觀地說,引用計(jì)數(shù)器法效率確實(shí)比較高,也容易實(shí)現(xiàn),但是它也有不足之處,就是 無用對(duì)象之間相互引用 的問題,這種情況的出現(xiàn)會(huì)導(dǎo)致相互引用的對(duì)象均無法被垃圾回收器回收。

可達(dá)性分析

為了解決 引用計(jì)數(shù)法 的無用對(duì)象循環(huán)引用導(dǎo)致無法被回收情況,JVM中又引入了 可達(dá)性分析 算法來判斷對(duì)象是否存活,這種算法也是普遍被應(yīng)用的方式。可達(dá)性分析基本思想:通過一系列被稱為“ GC Roots ”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索走過的路徑稱為 引用鏈 。當(dāng)一個(gè)對(duì)象到 GC Roots 沒有任何 引用鏈 相連接時(shí),則證明此對(duì)象不可用,即被判斷可回收對(duì)象??蛇_(dá)性分析算法示意圖如下圖所示:

那么,哪些對(duì)象可以作為 “GC Roots”呢?

虛擬機(jī)棧中( 局部變量表 )引用的對(duì)象;

方法區(qū)中類靜態(tài)屬性引用的對(duì)象;

方法區(qū)中常量引用的對(duì)象;

本地方法棧中Native方法引用的對(duì)象;

1.2.2 垃圾收集算法

前面我們通過 引用計(jì)數(shù)法 或 可達(dá)性分析 找到了哪些對(duì)象是可以被回收的,本節(jié)將重點(diǎn)闡述JVM中的垃圾回收器是如何將這些不可用對(duì)象進(jìn)行回收,即垃圾收集算法,主要包括 標(biāo)記-清除算法 、 復(fù)制算法 、 標(biāo)記-整理 以及 分代收集 等。相關(guān)介紹如下:

標(biāo)記-清除算法

標(biāo)記-清理算法是最基礎(chǔ)的垃圾收集算法,它的實(shí)現(xiàn)分為兩個(gè)階段,即 “標(biāo)記” 和 “清除” ,其中,標(biāo)記的作用為通過引用計(jì)數(shù)法或可達(dá)性分析算法標(biāo)記出所有需要回收的對(duì)象;清除的作用為在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。這種算法比較簡(jiǎn)單,但是缺陷也比較明顯,主要表現(xiàn)為兩個(gè)方面: 一是標(biāo)記和清理的效率比較低;二是標(biāo)記清理之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太大可能會(huì)導(dǎo)致以后在程序運(yùn)行過程中需要分配較大對(duì)象時(shí),無法找到足夠的連續(xù)內(nèi)存而不得不觸發(fā)另一次GC。 標(biāo)記-清除算法執(zhí)行過程如下圖所示:

復(fù)制算法

為了解決標(biāo)記-清理算法效率不高問題,人們提出了一種 復(fù)制算法 ,它的基本原理: 將可用內(nèi)存容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活的對(duì)象復(fù)制到另一塊上,然后再把已使用的內(nèi)存空間一次性清理掉。 這種方式實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效,且緩解了內(nèi)存碎片的問題,但是由于其只對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存分配、回收,從而導(dǎo)致可使用的內(nèi)存縮小為整個(gè)內(nèi)存的一半。復(fù)制算法執(zhí)行過程如下圖所示:

在HotSpot虛擬機(jī)中,整個(gè)內(nèi)存空間被分為一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 空間和其中的一塊 Survivor 空間。當(dāng)回收時(shí),將 Eden 和 Survivor 中還存活著的對(duì)象一次性復(fù)制到另一塊 Survivor 空間上,最后清理掉 Eden 和剛才用過的 Survivor 空間。HotSpot虛擬機(jī)默認(rèn) Eden 和 Surivor 的大小比例為 8:1:1 ,也就是每次新生代中可用內(nèi)存空間為整個(gè)內(nèi)存空間的90%,這就意味著有剩余的10%不可用。當(dāng) Survivor 空間不夠用時(shí),就需要依賴其他內(nèi)存( 老年代 )進(jìn)行分擔(dān)擔(dān)保。

注 :新生代是指剛創(chuàng)建不久的對(duì)象;老年代指被多次GC仍然存活的對(duì)象。

標(biāo)記-整理算法

雖說復(fù)制算法有效地提高了標(biāo)記-清除算法效率不高問題,但是在對(duì)象存活率較高的情況下,就需要進(jìn)行較多的復(fù)制操作(復(fù)制對(duì)象),尤其是所有對(duì)象都100%存活的極端情況,這種復(fù)r制算法效率將會(huì)大大降低,因此,老年代區(qū)域通常不會(huì)直接選用這種算法。根據(jù)老年代的特點(diǎn),有人提出了 標(biāo)記-整理算法 ,該算法基于標(biāo)記-清除算法發(fā)展而來,其中,標(biāo)記同標(biāo)記-清除算法一致,整理為 將所有存活的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。 標(biāo)記-整理算法執(zhí)行過程如下圖所示:

分代收集算法

分代收集算法是目前大部分虛擬機(jī)的垃圾收集器采用的算法,這種算法的思想是 根據(jù)對(duì)象的存活周期的不同將Java堆內(nèi)存劃分為幾塊,即新生代區(qū)域和老年代區(qū)域,然后對(duì)不同的區(qū)域采用合適的算法。 由于新生代每次GC時(shí)都會(huì)有大批對(duì)象死去,只有少量的對(duì)象存活,因此通常選用 復(fù)制算法 ;而老年代中因?yàn)榇婊盥矢?、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用“ 標(biāo)記-清理 “或” 標(biāo)記-整理 ”算法進(jìn)行回收。分代收集算法模型如下圖所示:

哪些對(duì)象能夠進(jìn)入老年代?

大對(duì)象;

每次Eden進(jìn)行GC后對(duì)象年齡加1進(jìn)入Survivor,對(duì)象年齡達(dá)到15時(shí)進(jìn)入老年代;

如果Survivor空間中相同年齡所有對(duì)象大小的總和大于survivor空間的一半,年齡大于等于該年齡的對(duì)象就直接進(jìn)入老年代。

如果survivor空間不能容納Eden中存活的對(duì)象,由于擔(dān)保機(jī)制會(huì)進(jìn)入老年代。如果survivor中的對(duì)象存活很多,擔(dān)保失敗,那么會(huì)進(jìn)行一次Full GC。

什么是Minor GC、Major GC和Full GC?

Minor GC從新生代空間(Eden和Survivor區(qū)域)回收內(nèi)存;

Major GC是清理永久代;

Full GC是清理整個(gè)堆內(nèi)存空間,包括新生代和永久代。

1.2.3 內(nèi)存分配與回收策略

Java的自動(dòng)內(nèi)存管理歸結(jié)于兩方面,即 為對(duì)象分配內(nèi)存 和 回收分配給對(duì)象的內(nèi)存 ,其中,在上一小節(jié)中我們?cè)敿?xì)闡述了回收內(nèi)存的具體細(xì)節(jié),這里不再討論。對(duì)于對(duì)象的內(nèi)存分配,實(shí)際上就是在Java堆中為對(duì)象分配內(nèi)存,準(zhǔn)確來說是在新生代的 Eden 區(qū)上,如果啟動(dòng)了本地線程分配緩沖,將按線程優(yōu)先在TLAB上分配,并且,少數(shù)情況下也可能會(huì)直接分配在老年代中??傊?,JVM中對(duì)對(duì)象內(nèi)存的分配不是固定的模式,其細(xì)節(jié)取決于使用哪種垃圾收集器,和虛擬機(jī)中與內(nèi)存相關(guān)的參數(shù)設(shè)置。常見的內(nèi)存分配策略:

對(duì)象優(yōu)先在Eden分配

大多數(shù)情況下,對(duì)象在Java堆的新生代Eden區(qū)中分配,當(dāng)Eden區(qū)沒有足夠空間進(jìn)行分配時(shí),虛擬機(jī)將發(fā)起一次 Minor GC 。

大對(duì)象直接進(jìn)入老年代

所謂的大對(duì)象是指需要大量連續(xù)內(nèi)存空間的Java對(duì)象,最典型的大對(duì)象就是那種 很長(zhǎng)的字符串 以及 數(shù)組 。對(duì)于內(nèi)存分配來說,大對(duì)象也是一個(gè)很棘手的東西,尤其是“短命大對(duì)象”,經(jīng)常出現(xiàn)在內(nèi)存空間還較多的情況下,大對(duì)象直接導(dǎo)致提前出發(fā)垃圾收集器以獲取足夠的連續(xù)空間來“安置”它們。

虛擬機(jī)提供了一個(gè) -XX:PretenureSizeThreshold 參數(shù),使得大于這個(gè)設(shè)置值得對(duì)象直接在老年代內(nèi)存區(qū)域分配,這樣做的目的在于避免在Eden區(qū)及兩個(gè)Survivor區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。

長(zhǎng)期存活的對(duì)象將進(jìn)入老年代

虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡(Age)計(jì)數(shù)器,如果對(duì)象在Eden出生并經(jīng)過第一次Minor GC后仍然存活,并且能被Survivor容納的話,將被移動(dòng)到Survivor空間中,并且對(duì)象年齡設(shè)為1.對(duì)象在Survivor區(qū)中每“熬過”一次Minor GC,年齡就增加1歲,當(dāng)它的年齡增加到一定程度( 默認(rèn)15歲 ),就將會(huì)被晉升到老年代中。虛擬機(jī)提供了一個(gè) -XX:MaxTenuringThreshold 參數(shù)設(shè)置老年代年齡閾值。

虛擬機(jī)并不是永遠(yuǎn)地要求對(duì)象的年齡必須達(dá)到了 -XX:MaxTenuringThreshold 才能晉升到老年代,如果在Survivor空間中相同年齡所有對(duì)象的大小的總和大于Survivor空間的一半,年齡大于或者等于該年齡的對(duì)象就可以直接進(jìn)入老年代,無須等到 -XX:MaxTenuringThreshold 中要求的年齡。

空間分配擔(dān)保

在發(fā)生 Minor GC 之前,虛擬機(jī)會(huì)先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對(duì)象總空間,如果這個(gè)條件成立,那么 Minor GC 可以確保是安全的;如果不成立,則虛擬機(jī)會(huì)查看 HandlePromotionFailure 設(shè)置值是否允許擔(dān)保失敗。如果允許,那么會(huì)繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對(duì)象的平均大小,如果大于,將嘗試著進(jìn)行一次 Minor GC ,盡管這次 Minor GC 是有風(fēng)險(xiǎn)的;如果小于,或者 HandlePromotionFailure 設(shè)置不允許冒險(xiǎn),那么這時(shí)就需要進(jìn)行一次 Full GC。

1.3 JVM的類加載機(jī)制

類從被加載到虛擬機(jī)內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括: 加載(Loading) 、 驗(yàn)證(Verification) 、 準(zhǔn)備(Preparation) 、 解析(Resolution) 、 初始化(Initialization) 、 使用(Using) 和 卸載(Unloading) 7個(gè)階段,其中,驗(yàn)證、準(zhǔn)備、解析3個(gè)部分統(tǒng)稱為連接(Linking)。類的生命周期如下圖所示:

在虛擬機(jī)中,我們常說的類的加載過程是指 加載(Loading) 、 驗(yàn)證(Verification) 、 準(zhǔn)備(Preparation) 、 解析(Resolution) 、 初始化(Initialization) 這五個(gè)階段,它們的具體作用為:

加載

加載過程是將二進(jìn)制字節(jié)流(Class字節(jié)碼文件)通過 類加載器 加載到內(nèi)存并實(shí)例化Class對(duì)象的過程( 加載到方法區(qū)內(nèi) )。這個(gè)過程獨(dú)立于虛擬機(jī)之外,并且二進(jìn)制流可以從不同的環(huán)境內(nèi)獲取或者由其他文件生成。

驗(yàn)證

驗(yàn)證Class文件的字節(jié)流是否符合虛擬機(jī)的要求,以免造成虛擬機(jī)出現(xiàn)異常。包括: 文件格式驗(yàn)證 、 元數(shù)據(jù)驗(yàn)證 、 字節(jié)碼驗(yàn)證 、 符號(hào)引用驗(yàn)證 。

準(zhǔn)備

為靜態(tài)變量( 被final關(guān)鍵字修飾 )分配內(nèi)存空間、賦值和設(shè)置類變量初始化(自動(dòng)初始化)。

解析

將常量池內(nèi)的 符號(hào)引用 替換為 直接引用 的過程。解析動(dòng)作主要針對(duì)類或接口、字段、類方法、接口方法、方法類型、方法句柄以及調(diào)用點(diǎn)限定符7類符號(hào)引用進(jìn)行。

初始化

執(zhí)行類構(gòu)造器 《clinit》 方法的過程,變量的聲明初始化就在這個(gè)階段進(jìn)行。

虛擬機(jī)類加載的時(shí)機(jī)?

1)遇到new、getstatic、putstatic或者invokestatic 這四條字節(jié)碼指令的時(shí)候,且該類沒有進(jìn)行初始化則進(jìn)行該類的初始化;

2)使用反射機(jī)制的時(shí)候;

3)初始化類的父類;

4)初始化虛擬機(jī)要執(zhí)行主類;

5)使用動(dòng)態(tài)語言特性的時(shí)候;

總之,當(dāng)對(duì)一個(gè)類進(jìn)行主動(dòng)引用的時(shí)候就會(huì)進(jìn)行初始化操作,而進(jìn)行被動(dòng)引用的時(shí)候便不會(huì)觸發(fā)類初始化操作,比如通過子類引用父類靜態(tài)字段時(shí)子類不會(huì)被初始化。

02

常見內(nèi)存泄漏與優(yōu)化

2.1 內(nèi)存泄漏

當(dāng)一個(gè)對(duì)象已經(jīng)不需要再使用本該被回收時(shí),另外一個(gè)正在使用的對(duì)象持有它的引用從而導(dǎo)致它不能被垃圾收集器回收,結(jié)果它們就一直存在于內(nèi)存中(通常指Java堆內(nèi)存),占用有效空間,永遠(yuǎn)無法被刪除。隨著內(nèi)存不斷泄漏,堆中的可用空間就不斷變小,這意味著為了執(zhí)行常用的程序,垃圾清理需要啟動(dòng)的次數(shù)越來越多,非常嚴(yán)重的話會(huì)直接造成應(yīng)用程序報(bào)OOM異常。

優(yōu)化/避免內(nèi)存泄漏原則:

涉及到使用Context時(shí),盡量使用Application的Context;

對(duì)于非靜態(tài)內(nèi)部類、匿名內(nèi)部類,需將其獨(dú)立出來或者改為靜態(tài)類;

在靜態(tài)內(nèi)部類中持有外部類(非靜態(tài))的對(duì)象引用,使用弱引用來處理;

不再使用的資源(對(duì)象),需顯示釋放資源(對(duì)象置為null),如果是集合需要清空;

保持對(duì)對(duì)象生命周期的敏感,尤其注意單例、靜態(tài)對(duì)象、全局性集合等的生命周期;

2.2 常見內(nèi)存泄漏與優(yōu)化

(1) 單例造成的內(nèi)存泄漏

案例

/** 工具類,單例模式 * @Auther: Jiangdg * @Date: 2019/10/8 17:23 * @Description: */public class CommonUtils { private static CommonUtils instance; private Context mCtx; private CommonUtils(Context context){ this.mCtx = context; } public static CommonUtils getInstance(Context context) { if(instance == null) { instance = new CommonUtils(context); } return instance; }}/**使用單例模式時(shí)造成內(nèi)存泄漏 * * @Auther: Jiangdg * @Date: 2019/10/8 17:24 * @Description: */public class SingleActivity extends AppCompatActivity { private CommonUtils mUtils; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUtils = CommonUtils.getInstance(this); }}

分析與優(yōu)化

在上述示例中,當(dāng)SingleActivity實(shí)例化Commontils對(duì)象完畢后,Commontils將持有SingleActivity對(duì)象的引用,而由于單例模式的靜態(tài)特性,Commontils對(duì)象的生命周期將于應(yīng)用進(jìn)程的一致,這就會(huì)導(dǎo)致在應(yīng)用未退出的情況下,如果SingleActivity對(duì)象已經(jīng)不再需要了,而Commontils對(duì)象該持有該對(duì)象的引用就會(huì)使得GC無法對(duì)其進(jìn)行正常回收,從而導(dǎo)致了內(nèi)存泄漏。優(yōu)化:對(duì)于需要傳入Context參數(shù)的情況,盡量使用Application的Context,因?yàn)樗鼤?huì)伴隨著應(yīng)用進(jìn)程的存在而存在。

public class SingleActivity extends AppCompatActivity { private CommonUtils mUtils; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 造成內(nèi)存泄漏 //mUtils = CommonUtils.getInstance(this); mUtils = CommonUtils.getInstance(this.getApplicationContext()); }}

(2) Handler造成的內(nèi)存泄漏

案例

/** 使用Handler造成內(nèi)存泄漏 * @Auther: Jiangdg * @Date: 2019/10/8 17:55 * @Description: */public class HandlerActivity extends AppCompatActivity { // 匿名內(nèi)部類 private Handler mUIHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); new Thread(new Runnable() { @Override public void run() { // 處理耗時(shí)任務(wù) // 。.. mUIHandler.sendEmptyMessage(0x00); } }); }}

分析與優(yōu)化

在剖析Handler消息機(jī)制原理一文中我們知道,在Android應(yīng)用啟動(dòng)時(shí),應(yīng)用程序的主線程會(huì)為其自動(dòng)創(chuàng)建一個(gè) Looper 對(duì)象和與之關(guān)聯(lián)的 MessageQueue ,當(dāng)主線程實(shí)例化一個(gè) Handler 對(duì)象后,它就自動(dòng)與主線程的 MessageQueue 關(guān)聯(lián)起來,所有發(fā)送到 MessageQueue 的 Message (消息)都會(huì)持有Handler的引用。由于 主線程的Looper對(duì)象會(huì)隨著應(yīng)用進(jìn)程一直存在的且Java類中的非靜態(tài)內(nèi)部類和匿名內(nèi)部類默認(rèn)持有外部類的引用 ,假如 HandlerActivity 提前出棧不使用了,但 MessageQueue 中仍然還有未處理的 Message , Looper 就會(huì)不斷地從 MessageQueue 取出消息交給 Handler 來處理,就會(huì)導(dǎo)致 Handler 對(duì)象一直持有 HandlerActivity 對(duì)象的引用,從而出現(xiàn) HandlerActivity 對(duì)象無法被GC正?;厥眨M(jìn)而造成內(nèi)存泄漏。優(yōu)化:將Handler類獨(dú)立出來,或者使用靜態(tài)內(nèi)部類,因?yàn)殪o態(tài)內(nèi)部類不持有外部類的引用。

public class HandlerActivity extends AppCompatActivity {// 匿名內(nèi)部類默認(rèn)持有HandlerActivity的引用// 造成內(nèi)存泄漏// private Handler mUIHandler = new Handler() {// @Override// public void handleMessage(Message msg) {// super.handleMessage(msg);// }// }; // 優(yōu)化,使用靜態(tài)內(nèi)部類 // 假如要持有HandlerActivity,以便在UIHandler中訪問其成員變量或成員方法 // 需要使用弱引用處理 private UIHandler mUIHandler; static class UIHandler extends Handler { private WeakReference《HandlerActivity》 mWfActivity; public UIHandler(HandlerActivity activity) { mWfActivity = new WeakReference《》(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); } } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUIHandler = new UIHandler(this); }}

Java中四種引用關(guān)系:

強(qiáng)引用

用來描述永遠(yuǎn)不會(huì)被垃圾收集器回收掉的對(duì)象,類似“Object obj = new Object”

軟引用

用來描述一些還有用但并非必須的對(duì)象,由 SoftReference 類實(shí)現(xiàn)。被軟引用關(guān)聯(lián)著的對(duì)象會(huì)在系統(tǒng)將要發(fā)生OOM之前,垃圾收集器才會(huì)回收掉這些對(duì)象。

弱引用

用來描述非必須的對(duì)象,比軟引用更弱一些,由 WeakReference 類實(shí)現(xiàn)。被弱引用的對(duì)象只能生產(chǎn)到下一次垃圾收集發(fā)生之前,無論當(dāng)前內(nèi)存是否足夠。

虛引用

最弱的引種引用關(guān)系,由 PhantomReference 類實(shí)現(xiàn)。一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間產(chǎn)生影響,也無法通過虛引用來獲取該對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的是能在這個(gè) 對(duì)象被垃圾收集器回收時(shí)收到一個(gè)系統(tǒng)通知 。

(3) 線程(非靜態(tài)內(nèi)部類或匿名內(nèi)部類)造成的內(nèi)存泄漏

案例

/** 使用線程造成的內(nèi)存泄漏 * @Auther: Jiangdg * @Date: 2019/10/9 10:04 * @Description: */public class ThreadActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 開啟一個(gè)子線程 new Thread(new MyRunnable()).start(); // 開啟一個(gè)異步任務(wù) new MyAsyncTask(this).execute(); } class MyRunnable implements Runnable { @Override public void run() { } } class MyAsyncTask extends AsyncTask { private Context mCtx; public MyAsyncTask(Context context) { this.mCtx = context; } @Override protected Object doInBackground(Object[] objects) { return null; } }}

分析與優(yōu)化

在之前的分析中可知,Java類中的非靜態(tài)內(nèi)部類和匿名內(nèi)部類默認(rèn)持有外部類的引用。對(duì)于上述示例中的 MyRunnable 和 MyAsyncTask 來說,它們是一個(gè) 非靜態(tài)內(nèi)部類 ,將默認(rèn)持有 ThreadActivity 對(duì)象的引用。假如子線程的任務(wù)在 ThreadActivity 銷毀之前還未完成,就會(huì)導(dǎo)致 ThreadActivity 無法被GC正?;厥眨斐蓛?nèi)存泄漏。優(yōu)化:將MyRunnable和MyAsyncTask獨(dú)立出來,或使用靜態(tài)內(nèi)部類,因?yàn)殪o態(tài)內(nèi)部類不持有外部類的引用。

public class ThreadActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 開啟一個(gè)子線程 new Thread(new MyRunnable()).start(); // 開啟一個(gè)異步任務(wù) // 優(yōu)化:使用Application的Context new MyAsyncTask(this.getApplicationContext()).execute(); } // 優(yōu)化:使用靜態(tài)內(nèi)部類 static class MyRunnable implements Runnable { @Override public void run() { } } // 優(yōu)化:使用靜態(tài)內(nèi)部類 // 如果需要傳入Context,使用Application的Context static class MyAsyncTask extends AsyncTask { private Context mCtx; public MyAsyncTask(Context context) { this.mCtx = context; } @Override protected Object doInBackground(Object[] objects) { return null; } }}

(4) 靜態(tài)實(shí)例造成的內(nèi)存泄漏

案例

/**非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例造成的內(nèi)存泄漏 * @Auther: Jiangdg * @Date: 2019/10/9 10:43 * @Description: */public class StaticInstanceActivity extends AppCompatActivity { private static SomeResources mSomeResources; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(mSomeResources == null) { mSomeResources = new SomeResources(this); } } class SomeResources { private Context mCtx; public SomeResources(Context context) { this.mCtx = context; } }}

分析與優(yōu)化

在上述案例中,演示了防止 StaticInstanceActivity 重建,比如橫豎屏切換,導(dǎo)致反復(fù)創(chuàng)建 SomeResources 實(shí)例的問題,這里使用了 static 修飾關(guān)鍵字將 SomeResources 實(shí)例聲明了靜態(tài)實(shí)例,以確保該實(shí)例始終存在的是同一個(gè),且它的生命周期與應(yīng)用相同。然而,由于 SomeResources 是一個(gè) 非靜態(tài)內(nèi)部類 ,其對(duì)象默認(rèn)持有外部類 StaticInstanceActivity 的引用,就會(huì)導(dǎo) SomeResources 的對(duì)象一直持有該引用,造成內(nèi)存泄漏。優(yōu)化:使用單例模式實(shí)現(xiàn)SomeResources,或者將其改成靜態(tài)內(nèi)部類。如果需要傳入Context參數(shù),必須使用Application的Context。

public class StaticInstanceActivity extends AppCompatActivity { private static SomeResources mSomeResources; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(mSomeResources == null) { // 優(yōu)化,使用Application的Context mSomeResources = new SomeResources(this.getApplicationContext()); } } // 優(yōu)化:使用靜態(tài)內(nèi)部類 static class SomeResources { private Context mCtx; public SomeResources(Context context) { this.mCtx = context; } }}

(5) 資源未關(guān)閉或監(jiān)聽器未移除(注銷)引起的內(nèi)存泄露情況

在開發(fā)中,如果使用了 BraodcastReceiver , ContentObserver , File , Cursor , Stream , Bitmap 、 自定義屬性attributeattr 、傳感器等資源,應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷,否則這些資源將不會(huì)被回收,從而造成內(nèi)存泄漏。比如:

// 使用傳感器等資源,需要注銷SensorManager sensorManager = getSystemService(SENSOR_SERVICE);Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);sensorManager.unregisterListener(listener);// 使用BraodcastReceiver,需要注銷Myreceiver recevier = new Myreceiver();intentFilter = new IntentFilter();intentFilter.addAction(“android.net.conn.CONNECTIVITY_CHANGE”);registerReceiver(recevier,intentFilter);unRegisterReceiver(recevier);// 自定義屬性,需要recycleTypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AttrDeclareView);int color = a.getColor(R.styleable.AttrDeclareView_background_color, 0);a.recycle();

除了上述常見的5種內(nèi)存泄漏外,還有包括 無限循環(huán)動(dòng)畫 、 使用ListView 、 使用集合容器 以及 使用WebView 也會(huì)造成內(nèi)存泄漏,其中,無限循環(huán)動(dòng)畫造成泄漏的原因是沒有再Activity的onDestory中停止動(dòng)畫;使用ListView造成泄漏的原因是構(gòu)造Adapter時(shí)沒有使用緩存的convertView;使用集合容器造成泄漏的原因是在不使用相關(guān)對(duì)象時(shí),沒有清理掉集合中存儲(chǔ)的對(duì)象引用。在優(yōu)化時(shí),在退出程序之前將集合中的元素(引用)全部清理掉,再置為null;使用WebView造成泄漏的原因是在不使用WebView時(shí)沒有調(diào)用其destory方法來銷毀它,導(dǎo)致其長(zhǎng)期占用內(nèi)存且不能被回收。在優(yōu)化時(shí),可以為WebView開啟另外一個(gè)進(jìn)程,通過AIDL與主線程進(jìn)行通信,便于WebVIew所在的進(jìn)程可以根據(jù)業(yè)務(wù)需要選擇合適的時(shí)機(jī)進(jìn)行銷毀。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Android
    +關(guān)注

    關(guān)注

    12

    文章

    3973

    瀏覽量

    130234
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    3124

    瀏覽量

    75266
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2989

    瀏覽量

    109616
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    請(qǐng)問如何優(yōu)化OpenVINO?工具套件中的內(nèi)存使用?

    運(yùn)行OpenVINO?推斷時(shí)找不到優(yōu)化內(nèi)存使用情況的方法。
    發(fā)表于 06-25 06:56

    在OpenVINO? C++代碼中啟用 AddressSanitizer 時(shí)的內(nèi)存泄漏怎么解決?

    在 OpenVINO? C++代碼中啟用 AddressSanitizer 時(shí)遇到內(nèi)存泄漏: \"#0 0xaaaab8558370 in operator new(unsigned
    發(fā)表于 06-23 07:16

    鴻蒙5開發(fā)寶藏案例分享---內(nèi)存優(yōu)化實(shí)戰(zhàn)指南

    Hey,各位鴻蒙開發(fā)者們! 大家有沒有這種感覺:官方文檔雖然全面,但有時(shí)候就像一座巨大的寶庫,里面藏著很多超實(shí)用的“金礦”,不仔細(xì)挖還真發(fā)現(xiàn)不了!最近我就意外挖到了關(guān)于****內(nèi)存優(yōu)化的寶藏章節(jié)
    發(fā)表于 06-12 17:15

    HarmonyOS優(yōu)化應(yīng)用內(nèi)存占用問題性能優(yōu)化

    一、使用purgeable優(yōu)化C++內(nèi)存 Purgeable Memory是HarmonyOS中native層常用的內(nèi)存管理機(jī)制,可用于圖像處理的Bitmap、流媒體應(yīng)用的一次性數(shù)據(jù)、圖片等
    發(fā)表于 05-24 17:20

    HarmonyOS優(yōu)化應(yīng)用內(nèi)存占用問題性能優(yōu)化

    應(yīng)用開發(fā)過程中注重內(nèi)存管理,積極采取措施來減少內(nèi)存占用,以優(yōu)化應(yīng)用程序的性能和用戶體驗(yàn)。 HarmonyOS提供了一些內(nèi)存管理的工具和接口,幫助開發(fā)者有效地管理
    發(fā)表于 05-21 11:27

    使用OpenVINO?進(jìn)行推理時(shí)的內(nèi)存泄漏怎么解決?

    使用 OpenVINO? 進(jìn)行推理時(shí),內(nèi)存會(huì)隨著時(shí)間的推移而增加,并導(dǎo)致程序崩潰。
    發(fā)表于 03-06 08:29

    內(nèi)存泄漏檢測(cè)工具Sanitizer介紹

    內(nèi)存泄漏,我們經(jīng)常會(huì)遇到,如何檢測(cè)內(nèi)存泄漏,除了我們之前講過的 valgrind,還可以使用 gcc 自帶的工具 sanitizer。
    的頭像 發(fā)表于 03-01 14:52 ?715次閱讀

    hyper 內(nèi)存,Hyper內(nèi)存:如何監(jiān)控與優(yōu)化hyper-v虛擬機(jī)的內(nèi)存使用

    :如何監(jiān)控與優(yōu)化hyper-v虛擬機(jī)的內(nèi)存使用。 ? ?在虛擬化環(huán)境中,合理監(jiān)控和優(yōu)化Hyper-V虛擬機(jī)的內(nèi)存使用對(duì)于提升性能和資源利用率至關(guān)重要。本文將詳細(xì)介紹如何監(jiān)控Hyper-
    的頭像 發(fā)表于 01-24 14:15 ?1100次閱讀
    hyper <b class='flag-5'>內(nèi)存</b>,Hyper<b class='flag-5'>內(nèi)存</b>:如何監(jiān)控與<b class='flag-5'>優(yōu)化</b>hyper-v虛擬機(jī)的<b class='flag-5'>內(nèi)存</b>使用

    虛擬內(nèi)存溢出該怎么處理 虛擬內(nèi)存在服務(wù)器中的應(yīng)用

    、虛擬內(nèi)存溢出的原因 內(nèi)存泄漏 :程序中未正確釋放的內(nèi)存會(huì)導(dǎo)致內(nèi)存泄漏,隨著時(shí)間的推移,這些
    的頭像 發(fā)表于 12-04 09:49 ?819次閱讀

    如何優(yōu)化RAM內(nèi)存使用

    優(yōu)化RAM內(nèi)存使用是一個(gè)重要的任務(wù),特別是對(duì)于那些擁有有限內(nèi)存資源的用戶。以下是一些優(yōu)化RAM內(nèi)存使用的策略,這些策略可以幫助您更有效地使用
    的頭像 發(fā)表于 11-11 09:58 ?1445次閱讀

    DRA7xx器件上的Android啟動(dòng)優(yōu)化

    電子發(fā)燒友網(wǎng)站提供《DRA7xx器件上的Android啟動(dòng)優(yōu)化.pdf》資料免費(fèi)下載
    發(fā)表于 10-11 09:41 ?0次下載
    DRA7xx器件上的<b class='flag-5'>Android</b>啟動(dòng)<b class='flag-5'>優(yōu)化</b>

    TinyMaix框架的內(nèi)存需求超過了APM32F411的可用內(nèi)存,導(dǎo)致運(yùn)行失敗,怎么能成功優(yōu)化?

    TinyMaix框架的內(nèi)存需求超過了APM32F411的可用內(nèi)存,導(dǎo)致運(yùn)行失敗。怎么能成功優(yōu)化?
    發(fā)表于 09-27 09:44

    堆棧和內(nèi)存的基本知識(shí)

    本文主要聊聊關(guān)于堆棧的內(nèi)容。包括堆棧和內(nèi)存的基本知識(shí)。常見和堆棧相關(guān)的 bug,如棧溢出,內(nèi)存泄漏,堆內(nèi)存分配失敗等。后面介紹軟件中堆棧統(tǒng)計(jì)的重要性,以及如何使用工具工具軟件中堆棧使用
    的頭像 發(fā)表于 08-29 14:10 ?1044次閱讀
    堆棧和<b class='flag-5'>內(nèi)存</b>的基本知識(shí)

    如何檢測(cè)內(nèi)存泄漏

    檢測(cè)內(nèi)存泄漏是軟件開發(fā)過程中一項(xiàng)至關(guān)重要的任務(wù),它有助于識(shí)別和解決那些導(dǎo)致程序占用過多內(nèi)存資源,從而影響程序性能甚至導(dǎo)致程序崩潰的問題。以下將詳細(xì)闡述幾種常見的內(nèi)存
    的頭像 發(fā)表于 07-30 11:50 ?3495次閱讀

    NONOS 1.5.3/1.5.4 SSL內(nèi)存泄漏的原因?

    我已經(jīng)通過隨附的代碼驗(yàn)證了當(dāng)發(fā)生 SSL 握手錯(cuò)誤時(shí),會(huì)生成內(nèi)存泄漏 此外,espconn_reconnect_callback不稱為信令ESPCONN_HANDSHAKE - TCP SSL 握手
    發(fā)表于 07-18 07:24