AJPFX談Java 性能優化之基本類型 vs 引用類型

★名詞定義
  先明確一下什麼是「基本類型」,什麼是「引用類型」。
  簡單地說,所謂基本類型就是 Java 語言中以下的8種內置類型:ide

boolean
char
byte
short
int
long
float
double
  而引用類型就是那些能夠經過 new 來建立對象的類型(基本上都是派生自 Object)。函數

★兩種類型的存儲方式
  這兩種類型的差別,首先體如今存儲方式上。性能

◇引用類型的建立
  當你在函數中建立一個引用類型的對象時,好比下面這句:操作系統

StringBuffer str = new StringBuffer();
  該 StringBuffer 【對象】的內容是存儲在堆(Heap)上的,須要申請堆內存。而變量 str 只不過是針對該 StringBuffer 對象的一個引用(或者叫地址)。變量 str 的【值】(也就是 StringBuffer 對象的地址)是存儲在【棧】上的。線程

◇基本類型的建立
  當你在【函數中}建立一個基本類型的變量時,好比下面這句:設計

int n = 123;
  這個變量 n 的【值】也是存儲在棧(Stack)上的,可是這個語句不須要再從堆中申請內存了。對象

  爲了更加形象,便於大夥兒理解,簡單畫了一個示意圖以下:進程

不見圖 請FQ內存

★堆和棧的性能差別
  可能有同窗會小聲問:堆和棧有啥區別捏?
  要說堆和棧的差異,那可就大了去了。若是你對這兩個概念仍是不太明白或者常常混淆,建議先找本操做系統的書拜讀一下。
  因爲是介紹性能,因此來討論一下堆和棧在性能方面的差異(這個差別是很大滴)。堆相對進程來講是全局的,可以被全部線程訪問;而棧是線程局部的,只能本線程訪問。打個比方,棧就比如我的小金庫,堆就比如國庫。你從我的小金庫拿錢去花,不須要辦什麼手續,拿了就花,可是錢數有限;而國庫裏面的錢雖然不少,可是每次申請花錢要打報告、蓋圖章、辦 N 多手續,耗時又費力。
  一樣道理,因爲堆是全部線程共有的,從堆裏面申請內存要進行相關的加鎖操做,所以申請堆內存的複雜度和時間開銷比棧要大不少;從棧裏面申請內存,雖然又簡單又快,可是棧的大小有限,分配不了太多內存。get

★當初爲啥這樣設計?
  可能有同窗又問了,幹嗎把兩種類型分開存儲,幹嗎不放到一塊兒捏?這個問題問得好!下面咱們就來揣測一下,當初 Java 爲啥設計成這樣。
  當年 Java 它爹(James Gosling)設計語言的時候,對於這個問題有點進退兩難。若是把各類東東都放置到棧中,顯然不現實,一來棧是線程私有的(不便於共享),二來棧的大小是有限的,三來棧的結構也間接限制了它的用途。那爲啥不把各類東東都放置到堆裏面捏?都放堆裏面,卻是能繞過上述問題,可是剛纔也提到了,申請堆內存要辦不少手續,太繁瑣。若是僅僅在函數中寫一個簡單的「int n = 0;」,也要到堆裏面去分配內存,那性能就大大滴差了(要知道 Java 是1995年生出來的,那年頭俺買了臺 PC 配【4兆內存】就屬豪華配置了)。
  冥思苦想以後,Java 它爹只好作了一個折中:把類型分爲「基本類型」和「引用類型」,二者使用不一樣的建立方式。這種差別從 Java 語法上也能夠看出來:引用類型老是用 new 建立對象(提醒一下:某些單鍵對象/單例對象,表面上沒用 new,可是在 getInstance() 內部也仍是用 new 建立的);而基本類型則【不須要】用 new 來建立。

★這樣設計的弊端
  順便跑題一下,斗膽評價 Java 它爹這種設計的弊端(但願 Java Fans 不要跟我急)。我我的認爲:這個折中的決策,帶來了許多深遠的影響,隨手舉出幾個例子:
一、因爲基本類型不是派生自 Object,所以不能算是純種的對象。這致使了 Java 的「【純】面向對象」招牌打了折扣(當年 Sun 總是吹噓 Java 是「純」OO 的語言,其實 Java 的 OO 是不夠純粹滴)。
二、因爲基本類型不是派生自 Object,出於某些場合(好比容器類)的考慮,不得不爲每一個基本類型加上對應的包裝類(好比 Integer、Byte 等),使得語言變得有點冗餘。

★結論  從上述的介紹,咱們應該明白,使用 new 建立對象的開銷是【不小】的。在程序中能避免就應該儘可能避免。另外,使用 new 建立對象,不光是建立時開銷大,未來垃圾回收時,銷燬對象也是有開銷的

相關文章
相關標籤/搜索