APP性能優化系列(一):基本概念

首先弄清楚一些基本的問題:

  • java的內存區域如何劃分?
  • java中的引用有哪些?如何運用?
  • 什麼是內存泄露?內存泄露發生的場景有哪些?
  • Garbage Collector(垃圾回收器)什麼是垃圾,什麼是非垃圾?

問題一、java的內存區域如何劃分?

  從抽象的JVM的角度去看分爲:堆(Heap),棧(Stacks),方法區(MethodArea),運行時常量池(RuntimeConstant Pool),本地方法棧(NativeMethod Stacks),PC Register(PC寄存器)。java

  • Heap內存的分配也叫作動態內存分配,java中運行環境用來分配給對象和JRE類的內存都在堆內存,C/C++有時候能夠用malloc或者new來申請分配一個內存。在C/C++可能須要本身負責釋放(java裏面直接依賴GC機制)。
  • Stack內存是相對於線程Thread而言的, 在執行函數(方法)時,函數一些內部變量的存儲均可以放在棧上面建立,函數執行結束的時候這些存儲單元就會自動被釋放掉。棧內存包括分配的運算速度很快,由於內置在處理器的裏面的。固然容量有限。 它保存線程中方法中短時間存在的變量值和對Heap中對象的引用等.

區別:堆是不連續的內存區域,堆空間比較靈活也特別大。 棧式一塊連續的內存區域,大小是有操做系統覺決定的。堆管理很麻煩,頻繁地new/remove會形成大量的內存碎片,這樣就會慢慢致使效率低下。對於棧的話,他先進後出,進出徹底不會產生碎片,運行效率高且穩定。算法

咱們一般說的內存泄露,GC,是針對Heap內存的. 由於Stack內存在函數出棧的時候就銷燬了。函數

public class A{
    int a = 1;
    Student s1 = new Student();
public void Test(){ int b = 1; Student s2 = new Student(); } }

請問a的內存在哪裏,b的內存在哪裏,s1,s2的內存在哪裏?記住下面兩句話。大數據

  • 成員變量所有存儲在堆中(包括基本數據類型,引用及引用的對象實體),由於他們屬於類,類對象最終仍是要被new出來的。
  • 局部變量的基本數據類型和引用存儲於棧當中,引用的對象實體存儲在堆中。由於他們屬於方法當中的變量,生命週期會隨着方法一塊兒結束。

因此答案就是a,s1, s2對象都在堆中,b和s2對象引用在棧中。spa

問題二、java中的引用有哪些?如何運用?

從JDK1.2版本開始,把對象的引用分爲四種級別,從而使程序能更加靈活的控制對象的生命週期。這四種級別由高到低依次爲:強引用、軟引用、弱引用和虛引用。操作系統

  • 強引用(StrongReference) :咱們使用的大部分引用實際上都是強引用,這是使用最廣泛的引用。若是一個對象具備強引用,那就相似於必不可少的生活用品,垃圾回收器毫不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。
  • 軟引用(SoftReference) :若是內存空間足夠,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。
  • 弱引用(WeakReference): 在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程, 所以不必定會很快發現那些只具備弱引用的對象。 弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
  • 虛引用(PhantomReference) : 若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。虛 引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序若是發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。

問題三、什麼是內存泄露?內存泄露發生的場景有哪些?

當一個對象已經不須要再使用了,本該被回收時,而有另一個正在使用的對象持有它的引用,從而就致使對象不能被回收。這種致使了本該被回收的對象不能被回收而停留在堆內存中,就產生了內存泄漏。線程

內存泄露的場景有不少。code

  • 非靜態內部類的靜態實例
    因爲內部類默認持有外部類的引用,而靜態實例屬於類。因此,當外部類被銷燬時,內部類仍然持有外部類的引用,導致外部類沒法被GC回收。所以形成內存泄露。對象

  • 類的靜態變量持有大數據對象
    靜態變量長期維持到大數據對象的引用,阻止垃圾回收。blog

  • 資源對象未關閉
    資源性對象如Cursor、Stream、Socket,Bitmap,應該在使用後及時關閉。未在finally中關閉,會致使異常狀況下資源對象未被釋放的隱患。

  • 註冊對象未反註冊
    咱們經常寫不少的Listener,未反註冊會致使觀察者列表裏維持着對象的引用,阻止垃圾回收。

  • Handler臨時性內存泄露

           Handler經過發送Message與主線程交互,Message發出以後是存儲在MessageQueue中的,有些Message也不是立刻就被處理的。

  • Context泄露

          這個太多了,不細說,單利模式寫的不恰當就屬於這種。

問題四、Garbage Collector(垃圾回收器)什麼是垃圾,什麼是非垃圾?

  • 什麼是GC?
    GC 是 garbage collection 的縮寫, 垃圾回收的意思. 也能夠是 Garbage Collector, 也就是垃圾回收器.
  •  

    根搜索算法是從離散數學中的圖論引入的,程序把全部的引用關係看做一張圖,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點之後,繼續尋找這個節點的引用節點,當全部的引用節點尋找完畢以後,剩餘的節點則被認爲是沒有被引用到的節點,即無用的節點。若是這個對象是引用可達的, 則稱之爲活的(live), 反之, 若是這個對象引用不可達, 則稱之爲死的(dead), 也能夠稱之爲垃圾(garbage).這個引用可達與不可達就是相對於GC Root來講的,在上圖中,左邊4個對象就是活的,右邊兩個就是死的,也就是咱們說的能夠被回收的垃圾。

     

    以上參考:https://www.jianshu.com/nb/8017467

相關文章
相關標籤/搜索