国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于Android的內(nèi)存泄漏與溢出研究

2018-03-10 00:30何群芳時(shí)招軍
軟件導(dǎo)刊 2018年2期

何群芳+時(shí)招軍

摘 要:內(nèi)存的泄漏與溢出是在進(jìn)行Android開發(fā)時(shí)最常見且棘手的問題之一。為了提高Android開發(fā)的質(zhì)量和效率,總結(jié)了Android的內(nèi)存泄漏與溢出的常見類型和解決方法。內(nèi)存泄漏的常見類型有集合類泄漏、傳入Activity的Context造成的內(nèi)存泄漏、非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例和線程造成的內(nèi)存泄漏等;內(nèi)存溢出的常見類型有由強(qiáng)引用造成的內(nèi)存溢出、由大量圖片顯示導(dǎo)致的內(nèi)存溢出、從數(shù)據(jù)庫中取出大量數(shù)據(jù)造成的內(nèi)存溢出、代碼中存在死循環(huán)或循環(huán)產(chǎn)生過多重復(fù)對象實(shí)體造成的內(nèi)存溢出等,并提出了由圖片造成的內(nèi)存溢出的新的解決方法。

關(guān)鍵詞:內(nèi)存管理;Android;內(nèi)存泄漏;內(nèi)存溢出

DOIDOI:10.11907/rjdk.172379

中圖分類號(hào):TP301

文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1672-7800(2018)002-0050-03

0 引言

Java的內(nèi)存管理即為對象的分配和釋放問題。在Java中,程序員需要通過關(guān)鍵字new為每個(gè)對象申請內(nèi)存空間(基本類型除外),所有對象都在堆(Heap)中分配空間。而對象的釋放由GC決定和執(zhí)行。該方式確實(shí)簡化了程序員的工作,但同時(shí)也加大了JVM的工作量。因?yàn)镚C為了能夠正確地釋放對象,必須監(jiān)控每一個(gè)對象的運(yùn)行狀態(tài),包括對象的申請、引用、被引用、賦值等[1-4]。

在Java中,內(nèi)存泄漏就是存在一些被分配的對象,這些對象存在以下兩個(gè)特點(diǎn):首先,這些對象是可達(dá)的,即在有向圖中,存在通路可以與其相連(也即是說仍存在對該對象的引用);其次,這些對象是無用的,即程序以后不會(huì)再使用這些對象。如果滿足這兩個(gè)條件,這些對象即可判定為Java中的內(nèi)存泄漏。內(nèi)存泄漏造成的后果在于內(nèi)存泄漏堆積,如果一直存在內(nèi)存泄漏,最終會(huì)導(dǎo)致越來越多內(nèi)存無法回收而又不能被利用,最終可用內(nèi)存越來越少。內(nèi)存溢出是程序占用的內(nèi)存大小超過了虛擬機(jī)(DVM)的允許值,而造成內(nèi)存溢出的最主要原因是高質(zhì)量圖片的大量出現(xiàn)。通過對Java內(nèi)存分配、內(nèi)存管理和垃圾回收原理的理解,總結(jié)導(dǎo)致內(nèi)存泄漏和內(nèi)存溢出的常見原因,并提出相應(yīng)預(yù)防措施,可有效提升程序質(zhì)量。

1 內(nèi)存泄漏與內(nèi)存溢出常見類型與解決方法

內(nèi)存泄漏(Memory Leak)是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果;內(nèi)存溢出(Out of Memory)通俗理解就是內(nèi)存不夠,通常在運(yùn)行大型軟件或游戲時(shí),軟件或游戲所需的內(nèi)存遠(yuǎn)遠(yuǎn)超出了主機(jī)內(nèi)安裝的內(nèi)存所能承受的大小,稱為內(nèi)存溢出。此時(shí)軟件或游戲無法運(yùn)行,系統(tǒng)會(huì)提示內(nèi)存溢出,有時(shí)甚至?xí)詣?dòng)關(guān)閉軟件,重啟電腦或軟件后釋放掉部分內(nèi)存,又可以正常運(yùn)行該軟件。

1.1 內(nèi)存泄漏常見類型與解決方法

1.1.1 集合類泄漏

集合類如果僅有添加元素的方法,而沒有相應(yīng)的刪除機(jī)制,可能導(dǎo)致內(nèi)存被占用。如果該集合類是全局性的變量 (比如類中的靜態(tài)屬性、全局性的 map 等即有靜態(tài)引用或 final 一直指向它),則沒有相應(yīng)的刪除機(jī)制,很可能導(dǎo)致集合占用的內(nèi)存只增不減,這就是集合類泄漏。

解決方法:給集合類添加相應(yīng)的刪除機(jī)制,最簡單的方法是直接將集合置為null。

1.1.2 傳入Activity的Context造成的內(nèi)存泄漏

因?yàn)锳ctivity的生命周期可能比引用該Activity的生命周期短,所以即使該Activity被銷毀,依然處于被引用狀態(tài),GC無法回收,造成內(nèi)存泄漏。例如在static的工具類中,在創(chuàng)建數(shù)據(jù)庫或打開數(shù)據(jù)庫、開啟系統(tǒng)服務(wù)與廣播時(shí)以及創(chuàng)建單例等情況下傳入Activity的Context,即使Activity被銷毀,GC依然無法回收該Activity所占用的資源,這就是由傳入Activity的Context造成的內(nèi)存泄漏。

解決方法:如果需要傳入Context,可以改用Application的Context,即getApplicationContext()。當(dāng)然,Application的Context也不是萬能的,基本上除了start a activity和show a dialog需要Activity的Context之外,其他的都可以用Application的Context替代。

1.1.3 非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例與線程造成的內(nèi)存泄漏

非靜態(tài)內(nèi)部類默認(rèn)持有外部類的引用,而該非靜態(tài)內(nèi)部類又創(chuàng)建了一個(gè)靜態(tài)實(shí)例,該實(shí)例的生命周期和應(yīng)用長度相同,將導(dǎo)致了該靜態(tài)實(shí)例一直會(huì)持有該Activity的引用,導(dǎo)致Activity的內(nèi)存資源不能正常回收。線程和非靜態(tài)內(nèi)部類相似。

解決方法:將非靜態(tài)的內(nèi)部類改為靜態(tài)的內(nèi)部類,并將對Activity的引用改為弱引用,使內(nèi)部類和線程的生命周期脫離Activity的生命周期,并且當(dāng)GC進(jìn)行回收時(shí),可以回收被弱引用的Activity等[5-8]。

1.2 內(nèi)存溢出常見類型與解決方法

1.2.1 由強(qiáng)引用造成的內(nèi)存溢出

若所有的引用都是強(qiáng)引用,則大量內(nèi)存會(huì)被占用,最終導(dǎo)致內(nèi)存溢出。

解決方法:使用弱引用或軟引用,軟引用的對象在內(nèi)存不足時(shí)可被GC回收,弱引用的對象在垃圾回收時(shí)可被回收。

1.2.2 由大量圖片顯示導(dǎo)致的內(nèi)存溢出

為解決由大量圖片顯示造成的內(nèi)存溢出,可以使用BitmapFactory.Options類,在返回參數(shù)時(shí),只返回Bitmap的尺寸大小,而不將其加載到內(nèi)存中,可有效減少內(nèi)存溢出。同時(shí)在加載完后調(diào)用system.gc()通知系統(tǒng)及時(shí)回收。

1.2.3 從數(shù)據(jù)庫中取出大量數(shù)據(jù)造成的內(nèi)存溢出endprint

檢查在數(shù)據(jù)庫查詢中,是否有一次獲得全部數(shù)據(jù)的查詢。一般而言,如果一次取十萬條記錄到內(nèi)存,就可能引起內(nèi)存溢出。該問題比較隱蔽,在上線前,數(shù)據(jù)庫中數(shù)據(jù)較少,通常運(yùn)行正常,上線后,數(shù)據(jù)庫中數(shù)據(jù)增多,一次查詢即有可能引起內(nèi)存溢出。因此,對于數(shù)據(jù)庫查詢,盡量采用分頁的方式查詢。

1.2.4 代碼中存在死循環(huán)或循環(huán)產(chǎn)生過多重復(fù)對象實(shí)體造成的內(nèi)存溢出

出現(xiàn)這種情況,只能通過查看日志找出產(chǎn)生該問題的原因,檢查代碼中是否有死循環(huán)、遞歸調(diào)用,或大循環(huán)重復(fù)產(chǎn)生的新對象實(shí)體。

1.2.5 內(nèi)存分配大小不夠

虛擬機(jī)默認(rèn)的內(nèi)存大小對于大程序來說可能根本不夠用,這時(shí)則需要手動(dòng)更改默認(rèn)的內(nèi)存大小。對于Android平臺(tái)而言,其托管層使用的Dalvik JavaVM從目前的表現(xiàn)看還有很多地方可以進(jìn)行優(yōu)化處理,比如在開發(fā)一些大型游戲或比較消耗資源的應(yīng)用中可能考慮手動(dòng)干涉GC處理,如使用 dalvik.system.VMRuntime類提供的setTargetHeapUtilization方法可以增強(qiáng)程序堆內(nèi)存的處理效率[9-11]。具體原理可以參考開源工程,使用方法代碼如下:

Private final static float HEAP_UTILIZATION=0.6f;

//在程序onCreate時(shí)調(diào)用

VMRuntime.getRuntime().setTargetHeapUtilization(HEAP_UTILIZATION);

//自定義堆內(nèi)存大小,如:

Private final static int HEAP_SIZE=8*1024*1024;

//設(shè)置最小堆內(nèi)存大小為8MB

VMRuntime.getRuntime().setMininumHeapSize(HEAP_SIZE);

2 由圖片造成內(nèi)存溢出的新解決方法與特點(diǎn)

2.1 解決方法

對于Android程序而言,大量高質(zhì)量圖片的顯示幾乎無法避免,這也是造成內(nèi)存溢出最常見的原因之一。常見的解決方法是由程序員考慮到每一個(gè)可能造成內(nèi)存溢出的情況,然后加以防范。但是若使用新組件RecyclerView,并改用RecyclerView.Adpter,則可以將由圖片造成的內(nèi)存溢出交由RecyclerView類解決。RecyclerView類主要關(guān)注的是資源的回收與重用。使用RecyclerView.Adpter的關(guān)鍵代碼如下:

public class SimpleAdapter extends RecyclerView.Adapter{

/**

使用RecyclerView.Adapter重點(diǎn)在于重載這兩個(gè)方法,第一個(gè)方法負(fù)責(zé)創(chuàng)建ViewHolder,第二個(gè)方法負(fù)責(zé)顯示ViewHolder。只要將ViewHolder創(chuàng)建好,剩下資源的回收和重用RecyclerView會(huì)自動(dòng)解決。

*/

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

}

public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {

}

另外,對于服務(wù)器上的圖片,Android端可以直接使用路徑訪問,不需要從服務(wù)器端下載到客戶端再進(jìn)行顯示。即使要緩存到Android本地,也可以直接保存路徑。

2.2 特點(diǎn)

使用該方法,不僅可以讓同一個(gè)fragment中的內(nèi)容類型不一樣,使單個(gè)頁面的內(nèi)容多元化,最主要的是RecyclerView不關(guān)心視圖問題,中心放在回收和重用上。由RecyclerView直接進(jìn)行資源的回收和利用,使程序員不需要再考慮是否會(huì)發(fā)生內(nèi)存溢出,節(jié)省程序員在該方面花費(fèi)的時(shí)間,提高程序編寫效率。

3 結(jié)語

內(nèi)存泄漏和內(nèi)存溢出是Android開發(fā)中最為常見且繁瑣的問題之一,在實(shí)際開發(fā)過程中想要徹底根除這兩個(gè)問題幾乎不可能,只能在編寫代碼時(shí)考慮全面,提前作好防范,養(yǎng)成良好的編程習(xí)慣,從而達(dá)到有效防止內(nèi)存泄露和內(nèi)存溢出的效果。通過對內(nèi)存泄漏和內(nèi)存溢出常見類型和解決方法的合理總結(jié)和歸納,可有效解決Android開發(fā)中遇到的一系列難點(diǎn)。

對內(nèi)存的管理,關(guān)鍵在于資源的及時(shí)回收以及對內(nèi)存泄漏的預(yù)防。內(nèi)存的回收主要是對圖片等其他對象的回收與利用。其中預(yù)防內(nèi)存泄漏最主要的方法是將對Activity的Context的傳入改為對Application的Context的傳入,因?yàn)樵诤芏郩I界面以及廣播等的使用過程中幾乎都需要用到Context,而如果用Activity的Context,那么幾乎整個(gè)應(yīng)用程序中都會(huì)遍布Activity的Context,從而導(dǎo)致Activity無法成功銷毀,最終導(dǎo)致內(nèi)存泄漏。所以在需要傳入Context時(shí),一定要謹(jǐn)慎思考其可行性。另一種預(yù)防內(nèi)存泄漏的方法是將對Activity的強(qiáng)引用改為弱引用或軟引用,使GC在回收時(shí),能成功回收該Activity所占用的內(nèi)存資源。

參考文獻(xiàn):

[1] 周志明.深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐[M].第2版.北京:機(jī)械工業(yè)出版社,2013:50-98.

[2] 張秀宏.自己動(dòng)手寫Java虛擬機(jī)[M].北京:機(jī)械工業(yè)出版社,2016:60-98.

[3] 葛一鳴.實(shí)戰(zhàn)Java虛擬機(jī)—JVM故障診斷與性能優(yōu)化[M].北京:電子工業(yè)出版社,2015:30-45.

[4] 高翔龍.Java虛擬機(jī)精講[M].北京:電子工業(yè)出版社,2015:88-98.

[5] 羅彧成.Android應(yīng)用性能優(yōu)化最佳實(shí)踐[M].北京:機(jī)械工業(yè)出版社,2017:70-110.

[6] 埃爾韋.Android應(yīng)用性能優(yōu)化[M].白龍,譯.北京:人民郵電出版社,2012:10-50.

[7] DOUG SILLARS.高性能Android應(yīng)用開發(fā)[M].王若蘭,周丹紅,譯.北京:人民郵電出版社,2016:98-119.

[8] 騰訊SNG專項(xiàng)測試團(tuán)隊(duì).Android移動(dòng)性能實(shí)戰(zhàn)[M].北京:電子工業(yè)出版社,2017: 50-152.

[9] 鐘世禮.深入解析Android虛擬機(jī)[M].北京:人民郵電出版社,2016:40-48.

[10] 張國印,吳艷霞. AndroidDalvik虛擬機(jī)結(jié)構(gòu)及機(jī)制剖析[M].北京:清華大學(xué)出版社,2014:1-20.

[11] 張子言.深入解析Android虛擬機(jī)[M].北京:清華大學(xué)出版社,2014:50-90.

松桃| 靖西县| 临西县| 深泽县| 伊宁市| 洛扎县| 苏州市| 定西市| 济宁市| 洪洞县| 汝南县| 陵水| 安吉县| 九龙县| 循化| 洪洞县| 淄博市| 仪陇县| 雅江县| 崇阳县| 济阳县| 呼伦贝尔市| 平和县| 怀柔区| 雅江县| 玉山县| 汾阳市| 错那县| 临清市| 牡丹江市| 佛教| 珠海市| 郸城县| 镇安县| 三河市| 安丘市| 陆良县| 噶尔县| 景洪市| 兰坪| 阜城县|