與windows內存區別java
在Linux中常常發現空閒內存不多,彷佛全部的內存都被系統佔用了,表面感受是內存不夠用了,其實否則。這是Linux內存管理的一個優秀特性,在這方面,區別於 Windows的內存管理。主要特色是,不管物理內存有多大,Linux都將其充份利用,將一些程序調用過的硬盤數據讀入內存,利用內存讀寫的高速特性來提升Linux系統的數據訪問性能。而Windows是隻在須要內存時,才爲應用程序分配內存,並不能充分利用大容量的內存空間。換句話說,每增長一些物理內存,Linux都將能充分利用起來,發揮了硬件投資帶來的好處,而Windows只將其作爲擺設,即便增長8GB甚至更大。android
Android內存的意義程序員
其實咱們在用安卓手機的時候不用太在乎剩餘內存,Android上的應用是Java,固然須要虛擬機,而android上的應用是帶有獨立虛擬機的,也就是每開一個應用就會打開一個獨立的虛擬機。其實和java的垃圾回收機制相似,系統有一個規則來回收內存。進行內存調度有個閥值,只有低於這個值系統纔會按一個列表來關閉用戶不須要的東西。固然這個值默認設置得很小,因此你會看到內存老在不多的數值徘徊。但事實上他並不影響速度。相反加快了下次啓動應用的速度。這原本就是 android標榜的優點之一,若是人爲去關閉進程,沒有太大必要。特別是使用自動關進程的軟件。爲何內存少的時候運行大型程序會慢呢,緣由是:在內存剩餘很少時打開大型程序時會觸發系統自身的調進程調度策略,這是十分消耗系統資源的操做,特別是在一個程序頻繁向系統申請內存的時候。這種狀況下系統並不會關閉全部打開的進程,而是選擇性關閉,頻繁的調度天然會拖慢系統。算法
Android的內存管理編程
Android的程序由Java語言編寫,因此Android的內存管理與Java的內存管理類似。程序員經過new爲對象分配內存,全部對象在java堆內分配空間;然而對象的釋放是由垃圾回收器來完成的。C/C++中的內存機制是「誰污染,誰治理」,java的就比較人性化了,給咱們請了一個專門的清潔工(GC)。windows
GC 多線程
GC是垃圾收集的意思(GabageCollection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操做方法。框架
觸發主GC(Garbage Collector)的條件函數
JVM進行次GC的頻率很高,但由於這種GC佔用時間極短,因此對系統產生的影響不大。更值得關注的是主GC的觸發條件,由於它對系統影響很明顯。總的來講,有兩個條件會觸發主GC:性能
1)當應用程序空閒時,即沒有應用線程在運行時,GC會被調用。由於GC在優先級最低的線程中進行,因此當應用忙時,GC線程就不會被調用,但如下條件除外。
2)Java堆內存不足時,GC會被調用。當應用線程在運行,並在運行過程當中建立新對象,若這時內存空間不足,JVM就會強制地調用GC線程,以便回收內存用於新的分配。若GC一次以後仍不能知足內存分配的要求,JVM會再進行兩次GC做進一步的嘗試,若仍沒法知足要求,則 JVM將報「out of memory」的錯誤,Java應用將中止。
因爲是否進行主GC由JVM根據系統環境決定,而系統環境在不斷的變化當中,因此主GC的運行具備不肯定性,沒法預計它什麼時候必然出現,但能夠肯定的是對一個長期運行的應用來講,其主GC是反覆進行的。
減小GC開銷的措施
根據上述GC的機制,程序的運行會直接影響系統環境的變化,從而影響GC的觸發。若不針對GC的特色進行設計和編碼,就會出現內存駐留等一系列負面影響。爲了不這些影響,基本的原則就是儘量地減小垃圾和減小GC過程當中的開銷。具體措施包括如下幾個方面:
(1)不要顯式調用System.gc()
此函數建議JVM進行主GC,雖然只是建議而非必定,但不少狀況下它會觸發主GC,從而增長主GC的頻率,也即增長了間歇性停頓的次數。
(2)儘可能減小臨時對象的使用
臨時對象在跳出函數調用後,會成爲垃圾,少用臨時變量就至關於減小了垃圾的產生,從而延長了出現上述第二個觸發條件出現的時間,減小了主GC的機會。
(3)對象不用時最好顯式置爲Null
通常而言,爲Null的對象都會被做爲垃圾處理,因此將不用的對象顯式地設爲Null,有利於GC收集器斷定垃圾,從而提升了GC的效率。
(4)儘可能使用StringBuffer,而不用String來累加字符串
因爲String是固定長的字符串對象,累加String對象時,並不是在一個String對象中擴增,而是從新建立新的String對象,如Str5=Str1+Str2+Str3+Str4,這條語句執行過程當中會產生多個垃圾對象,由於對次做「+」操做時都必須建立新的String對象,但這些過渡對象對系統來講是沒有實際意義的,只會增長更多的垃圾。避免這種狀況能夠改用StringBuffer來累加字符串,因StringBuffer是可變長的,它在原有基礎上進行擴增,不會產生中間對象。
(5)能用基本類型如Int,Long,就不用Integer,Long對象
基本類型變量佔用的內存資源比相應對象佔用的少得多,若是沒有必要,最好使用基本變量。
(6)儘可能少用靜態對象變量
靜態變量屬於全局變量,不會被GC回收,它們會一直佔用內存。
(7)分散對象建立或刪除的時間
集中在短期內大量建立新對象,特別是大對象,會致使忽然須要大量內存,JVM在面臨這種狀況時,只能進行主GC,以回收內存或整合內存碎片,從而增長主GC的頻率。集中刪除對象,道理也是同樣的。它使得忽然出現了大量的垃圾對象,空閒空間必然減小,從而大大增長了下一次建立新對象時強制主GC的機會。
通過上述的說明,能夠發現垃圾回收有如下的幾個特色:
(1)垃圾收集發生的不可預知性:因爲實現了不一樣的垃圾回收算法和採用了不一樣的收集機制,因此它有多是定時發生,有多是當出現系統空閒CPU資源時發生,也有多是和原始的垃圾收集同樣,等到內存消耗出現極限時發生,這與垃圾收集器的選擇和具體的設置都有關係。
(2)垃圾收集的精確性:主要包括2 個方面:(a)垃圾收集器可以精確標記活着的對象;(b)垃圾收集器可以精確地定位對象之間的引用關係。前者是徹底地回收全部廢棄對象的前提,不然就可能形成內存泄漏。然後者則是實現歸併和複製等算法的必要條件。全部不可達對象都可以可靠地獲得回收,全部對象都可以從新分配,容許對象的複製和對象內存的縮並,這樣就有效地防止內存的支離破碎。
(3)如今有許多種不一樣的垃圾收集器,每種有其算法且其表現各異,既有當垃圾收集開始時就中止應用程序的運行,又有當垃圾收集開始時也容許應用程序的線程運行,還有在同一時間垃圾收集多線程運行。
(4)垃圾收集的實現和具體的JVM 以及JVM的內存模型有很是緊密的關係。不一樣的JVM 可能採用不一樣的垃圾收集,而JVM 的內存模型決定着該JVM能夠採用哪些類型垃圾收集。如今,HotSpot 系列JVM中的內存系統都採用先進的面向對象的框架設計,這使得該系列JVM均可以採用最早進的垃圾收集。
(5)隨着技術的發展,現代垃圾收集技術提供許多可選的垃圾收集器,並且在配置每種收集器的時候又能夠設置不一樣的參數,這就使得根據不一樣的應用環境得到最優的應用性能成爲可能。
針對以上特色,咱們在使用的時候要注意:
(1)不要試圖去假定垃圾收集發生的時間,這一切都是未知的。好比,方法中的一個臨時對象在方法調用完畢後就變成了無用對象,這個時候它的內存就能夠被釋放。
(2)Java中提供了一些和垃圾收集打交道的類,並且提供了一種強行執行垃圾收集的方法--調用System.gc(),但這一樣是個不肯定的方法。Java 中並不保證每次調用該方法就必定可以啓動垃圾收集,它只不過會向JVM發出這樣一個申請,究竟是否真正執行垃圾收集,一切都是個未知數。
(3)挑選適合本身的垃圾收集器。通常來講,若是系統沒有特殊和苛刻的性能要求,能夠採用JVM的缺省選項。不然能夠考慮使用有針對性的垃圾收集器,好比增量收集器就比較適合實時性要求較高的系統之中。系統具備較高的配置,有比較多的閒置資源,能夠考慮使用並行標記/清除收集器。
(4)關鍵的也是難把握的問題是內存泄漏。良好的編程習慣和嚴謹的編程態度永遠是最重要的,不要讓本身的一個小錯誤致使內存出現大漏洞。
(5)儘早釋放無用對象的引用。大多數程序員在使用臨時變量的時候,都是讓引用變量在退出活動域(scope)後,自動設置爲null,暗示垃圾收集器來收集該對象,還必須注意該引用的對象是否被監聽,若是有,則要去掉監聽器,而後再賦空值。
垃圾回收的優勢和原理
Java語言中一個顯著的特色就是引入了垃圾回收機制,使得Java程序員在編寫程序的時候再也不須要考慮內存管理。垃圾回收能夠有效的防止內存泄露,有效的使用可使用的內存。垃圾回收器一般是做爲一個單獨的低級別的線程運行,不可預知的狀況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清楚和回收,程序員不能實時的調用垃圾回收器對某個對象或全部對象進行垃圾回收。回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。程序員能夠手動執行System.gc(),通知GC運行,可是Java語言規範並不保證GC必定會執行。
² Android系統中GC出現內存泄露
致使內存泄漏主要的緣由是,先前申請了內存空間而忘記了釋放。若是程序中存在對無用對象的引用,那麼這些對象就會駐留內存,消耗內存,由於沒法讓垃圾回收器GC驗證這些對象是否再也不須要。若是存在對象的引用,這個對象就被定義爲"有效的活動",同時不會被釋放。要肯定對象所佔內存將被回收,咱們就要務必確認該對象再也不會被使用。典型的作法就是把對象數據成員設爲null或者從集合中移除該對象。但當局部變量不須要時,不需明顯的設爲null,由於一個方法執行完畢時,這些引用會自動被清理。Java 內存泄露的根本緣由就是 保存了不可能再被訪問的變量類型的引用。
Android的內存溢出
由於系統爲每個dalvik虛擬機分配的內存是有限的,它的最大堆大小通常是16M,有的機器爲24M。也就是說咱們所能利用的內存空間是有限的。若是咱們的內存佔用超過了必定的水平就會出現OutOfMemory的錯誤。
內存不夠用的緣由
因爲咱們程序的失誤,長期保持某些資源(如Context)的引用,形成內存泄露,資源形成得不到釋放。保存了多個耗用內存過大的對象(如Bitmap),形成內存超出限制。