成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

內存泄露從入門到精通三部曲之基礎知識篇

移動開發
為了判斷Java中是否有內存泄露,我們首先必須了解Java是如何管理(堆)內存的。Java的內存管理就是對象的分配和釋放問題。在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程序員不需要通過調用函數來釋放內存,但它只能回收無用并且不再被其它對象引用的那些對象所占用的空間。

一、首先以一個內存泄露實例來開始本節基礎概念的內容:

實例1:(單例導致內存對象無法釋放而泄露)

可以看出ImageUtil這個工具類是一個單例,并引用了activity的context。

試想這個場景,應用起來以后,轉屏。轉屏以后,舊MainActivity會destroy,新MainActivity會重建,導致單例ImageUtil重新getInstance。很不幸的是,由于instance已經不是空的了,所以ImageUtil不會重建,還持有之前的Context,也就是之前的那個MainActivity實例的context,因此會造成兩個問題:

功能問題:使用ImageUitl訪問context相關內容時可能會發生異常(因為當前context并不是當前activity的context);

內存泄露:舊context被生命周期更長的靜態變量持有而導致activity無法釋放造成泄漏!(因此靜態變量是很容易因此內存泄露的!)

使用工具可以看到ImageUtil引用了MainActivity導致MainActivity駐留內存發生泄漏。

備注:本系列部分概念和例子引用來自網絡。

二、內存泄露,我們要研究的泄露對象到底是什么?

首先我們來了解程序運行時,所需內存的分配策略:

按照編譯原理的觀點,程序運行時的內存分配有三種策略,分別是靜態的,棧式的,和堆式的,對應的,三種存儲策略使用的內存空間主要分別是靜態存儲區(也稱方法區)、堆區和棧區。他們的功能不同,對他們使用方式也就不同。

靜態存儲區(方法區):內存在程序編譯的時候就已經分配好,這塊內存在程序整個運行期間都存在。它主要存放靜態數據、全局static數據和常量。

棧區:在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。

堆區:亦稱動態內存分配。程序在運行的時候用malloc或new申請任意大小的內存,程序員自己負責在適當的時候用free或delete釋放內存(Java則依賴垃圾回收器)。動態內存的生存期可以由我們決定,如果我們不釋放內存,程序將在***才釋放掉動態內存。 但是,良好的編程習慣是:如果某動態內存不再使用,需要將其釋放掉。

接下來我們集中說下堆和棧的區別:

在函數中(說明是局部變量)定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個變量時,java就在棧中為這個變量分配內存空間,當超過變量的作用域后,java會自動釋放掉為該變量分配的內存空間,該內存空間可以立刻被另作他用。

堆內存用于存放所有由new創建的對象(內容包括該對象其中的所有成員變量)和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。在堆中產生了一個數組或者對象后,還可以在棧中定義一個特殊的變量,這個變量的取值等于數組或者對象在堆內存中的首地址,在棧中的這個特殊的變量就變成了數組或者對象的引用變量,以后就可以在程序中使用棧內存中的引用變量來訪問堆中的數組或者對象,引用變量相當于為數組或者對象起的一個別名,或者代號。

堆是不連續的內存區域(因為系統是用鏈表來存儲空閑內存地址,自然不是連續的),堆大小受限于計算機系統中有效的虛擬內存(32bit系統理論上是4G),所以堆的空間比較靈活,比較大。棧是一塊連續的內存區域,大小是操作系統預定好的,windows下棧大小是2M(也有是1M,在編譯時確定,VC中可設置)。

對于堆,頻繁的new/delete會造成大量內存碎片,使程序效率降低。對于棧,它是先進后出的隊列,進出一一對應,不產生碎片,運行效率穩定高。

舉一個關于變量存儲位置的實例2:

結論:

局部變量的基本數據類型和引用存儲于棧中,引用的對象實體存儲于堆中。

——因為它們屬于方法中的變量,生命周期隨方法而結束。

成員變量全部存儲與堆中(包括基本數據類型,引用和引用的對象實體)

——因為它們屬于類,類對象終究是要被new出來使用的。

回到我們的問題:內存泄露需要關注的是什么?

我們這里說的內存泄露,是針對,也只針對堆內存,他們存放的就是引用指向的對象實體。

三、那么第二個問題就是,內存為什么會泄露?

為了判斷Java中是否有內存泄露,我們首先必須了解Java是如何管理(堆)內存的。Java的內存管理就是對象的分配和釋放問題。在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程序員不需要通過調用函數來釋放內存,但它只能回收無用并且不再被其它對象引用的那些對象所占用的空間。

Java的內存垃圾回收機制是從程序的主要運行對象(如靜態對象/寄存器/棧上指向的堆內存對象等)開始檢查引用鏈,當遍歷一遍后得到上述這些無法回收的對象和他們所引用的對象鏈,組成無法回收的對象集合,而其他孤立對象(集)就作為垃圾回收。GC為了能夠正確釋放對象,必須監控每一個對象的運行狀態,包括對象的申請、引用、被引用、賦值等,GC都需要進行監控。監視對象狀態是為了更加準確地、及時地釋放對象,而釋放對象的根本原則就是該對象不再被引用。

在Java中,這些無用的對象都由GC負責回收,因此程序員不需要考慮這部分的內存泄露。雖然,我們有幾個函數可以訪問GC,例如運行GC的函數System.gc(),但是根據Java語言規范定義,該函數不保證JVM的垃圾收集器一定會執行。因為不同的JVM實現者可能使用不同的算法管理GC。通常GC的線程的優先級別較低。JVM調用GC的策略也有很多種,有的是內存使用到達一定程度時,GC才開始工作,也有定時執行的,有的是平緩執行GC,有的是中斷式執行GC。但通常來說,我們不需要關心這些。

至此,我們來看看Java中需要被回收的垃圾:

 

  1. { 
  2.  
  3. Person p1 = new Person(); 
  4.  
  5. …… 
  6.  
  7. } 

引用句柄p1的作用域是從定義到“}”處,執行完這對大括號中的所有代碼后,產生的Person對象就會變成垃圾,因為引用這個對象的句柄p1已超過其作用域,p1失效,在棧中被銷毀,因此堆上的Person對象不再被任何句柄引用了。 因此person變為垃圾,會被回收。

從上面的例子和解釋,可以看到一個很關鍵的詞:引用。

通俗的講,通過A能調用并訪問到B,那就說明A持有B的引用,或A就是B的引用,B的引用計數+1.

(1)比如 Person p1 = new Person();通過P1能操作Person對象,因此P1是Person的引用;

(2)比如類O中有一個成員變量是I類對象,因此我們可以使用o.i的方式來訪問I類對象的成員,因此o持有一個i對象的引用。

GC過程與對象的引用類型是嚴重相關的,我們來看看Java對引用的分類Strong reference, SoftReference, WeakReference, PhatomReference

講多一步,這里的軟引用/弱引用一般是做什么的呢?

在Android應用的開發中,為了防止內存溢出,在處理一些占用內存大而且聲明周期較長的對象時候,可以盡量應用軟引用和弱引用技術。

軟/弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。利用這個隊列可以得知被回收的軟/弱引用的對象列表,從而為緩沖器清除已失效的軟/弱引用。

假設我們的應用會用到大量的默認圖片,比如應用中有默認的頭像,默認游戲圖標等等,這些圖片很多地方會用到。如果每次都去讀取圖片,由于讀取文件需要硬件操作,速度較慢,會導致性能較低。所以我們考慮將圖片緩存起來,需要的時候直接從內存中讀取。但是,由于圖片占用內存空間比較大,緩存很多圖片需要很多的內存,就可能比較容易發生OutOfMemory異常。這時,我們可以考慮使用軟/弱引用技術來避免這個問題發生。以下就是高速緩沖器的雛形:

首先定義一個HashMap,保存軟引用對象。

  1. 1.private Map<String, SoftReference<Bitmap>>imageCache = new HashMap<String, SoftReference<Bitmap>>(); 

再來定義一個方法,保存Bitmap的軟引用到HashMap。

 

  1. public class CacheBySoftRef { 
  2.  
  3. // 首先定義一個HashMap,保存軟引用對象。 
  4.  
  5. private Map<String, SoftReference<Bitmap>>imageCache = new HashMap<String, SoftReference<Bitmap>>(); 
  6.  
  7. // 再來定義一個方法,保存Bitmap的軟引用到HashMap。 
  8.  
  9. public void addBitmapToCache(String path) { 
  10.  
  11. // 強引用的Bitmap對象 
  12.  
  13. Bitmap bitmap = BitmapFactory.decodeFile(path); 
  14.  
  15. // 軟引用的Bitmap對象 
  16.  
  17. SoftReference<Bitmap>softBitmap = new SoftReference<Bitmap>(bitmap); 
  18.  
  19. // 添加該對象到Map中使其緩存 
  20.  
  21. imageCache.put(path, softBitmap); 
  22.  
  23.  
  24. // 獲取的時候,可以通過SoftReference的get()方法得到Bitmap對象。 
  25.  
  26. public Bitmap getBitmapByPath(String path) { 
  27.  
  28. // 從緩存中取軟引用的Bitmap對象 
  29.  
  30. SoftReference<Bitmap>softBitmap = imageCache.get(path); 
  31.  
  32. // 判斷是否存在軟引用 
  33.  
  34. if (softBitmap == null) { 
  35.  
  36. return null
  37.  
  38.  
  39. // 通過軟引用取出Bitmap對象,如果由于內存不足Bitmap被回收,將取得空 ,如果未被回收,則可重復使用,提高速度。 
  40.  
  41. Bitmap bitmap = softBitmap.get(); 
  42.  
  43. return bitmap; 
  44.  
  45.  

使用軟引用以后,在OutOfMemory異常發生之前,這些緩存的圖片資源的內存空間可以被釋放掉的,從而避免內存達到上限,避免Crash發生。

如果只是想避免OutOfMemory異常的發生,則可以使用軟引用。如果對于應用的性能更在意,想盡快回收一些占用內存比較大的對象,則可以使用弱引用。

另外可以根據對象是否經常使用來判斷選擇軟引用還是弱引用。如果該對象可能會經常使用的,就盡量用軟引用。如果該對象不被使用的可能性更大些,就可以用弱引用。

回到我們的問題,為什么內存會泄露?

堆內存中的長生命周期的對象持有短生命周期對象的強/軟引用,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是Java中內存泄露的根本原因。

騰訊Bugly,國內Crash監控、統計的專業平臺,為開發者提供NDK錯誤支持、精準問題定位、ANR上報、自定義Log上報、智能合并分析等多項服務,問題實時上報,減少用戶流失。

責任編輯:倪明 來源: 騰訊Bugly
相關推薦

2015-11-18 09:28:44

內存泄露入門

2015-11-24 14:32:09

內存泄漏原因用戶實踐

2009-09-14 09:04:17

CCNA考試CCNA

2011-03-25 09:56:40

Nagios 安裝

2011-03-09 09:30:52

Mina

2010-07-17 01:12:31

Telnet服務

2010-09-26 14:39:40

DHCP故障分析

2010-09-14 16:54:18

2011-08-03 10:33:05

網絡管理網絡拓撲管理

2013-06-28 09:35:04

Hypervisor虛擬化成本

2010-09-06 09:22:26

CSS語法

2011-03-21 09:22:46

Tomcat

2022-10-10 09:10:51

家庭網絡網絡

2017-02-07 14:50:39

華為

2017-04-11 09:07:20

互聯網

2015-05-12 10:42:53

程序員代碼

2012-09-10 16:19:00

云計算公共云

2011-03-28 16:52:08

用戶體驗Android

2013-12-27 13:05:56

搜狗網址導航

2011-08-29 16:26:50

魔獸世界LUA
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区在线看 | 伊人狠狠 | 国产精品18hdxxxⅹ在线 | 国产精品一区二 | 激情五月婷婷综合 | 九九看片| 国产精品亚洲二区 | 九色 在线| 色综合色综合 | 欧美一区不卡 | 欧美日韩不卡合集视频 | 天天做日日做 | 精品一区二区三区不卡 | 91原创视频在线观看 | 精品视频一区二区 | 久久99视频免费观看 | 国产亚洲网站 | 伊人导航 | 久久久蜜臀国产一区二区 | 欧美激情视频一区二区三区在线播放 | 97超碰站 | 日本福利视频 | 精品欧美一区二区在线观看 | 毛片网在线观看 | 国产一级片精品 | 一级片av| 久久福利网站 | 婷婷综合五月天 | 国产高清免费视频 | 精品福利一区二区三区 | 免费观看一级毛片 | 久久久成人免费一区二区 | 国产精品毛片一区二区在线看 | 天天插天天射天天干 | 精品视频免费在线 | 99久久精品国产一区二区三区 | 日韩电影一区 | 中文字幕视频在线观看免费 | 国产黄色一级片 | 日韩欧美在线一区 | 欧美在线视频一区 |