1、java語言java
1.1 支持面向對象編程oop算法
強調支持,由於java一樣能夠面向過程編程,但java是爲oop而生的。編程
oop的三大特性是:封裝、繼承、多態。多線程
封裝主要針對成員變量而言,oop的思想要求成員變量均爲私有,不該該對外可以訪問,一個符合oop思想的類應該只有公共方法對外可以訪問;併發
繼承,主要理解繼承體系,private、protected、public在繼承中的使用場景。理解java是單繼承多實現的(與C++的區別);jvm
多態主要指一個類的實例是運行時決定的,而不是聲明時決定的。父類 a = new 子類();是能夠的。這種做用在於能夠面向抽象編程、面向接口編程,對象沒必要必須和聲明的類一致,只要是它的子類、孫子類等便可;oop
1.2 jdk版本對java語言的改進優化
1996年發佈jdk1.0,java語言具有基礎的oop語法;線程
1997年發佈jdk1.1,引入內部類;設計
2004年發佈jdk1.5,引入語法糖,自動拆裝箱、泛型、動態註解、枚舉、可變長參數、遍歷循環(foreach);
2014年發佈jdk8,引入Lambda表達式;
2、jvm虛擬機(本文特指官方默認的HotSpot虛擬機)
2.1 發展
由一家小公司Longview Technologies開發出來,1997年被sun公司收購,jdk1.3以後正式成爲官方默認虛擬機;
HotSpot得名於其熱點代碼探測技術,能夠有效的把熱點代碼探測出來,並利用JIT編譯器將熱點代碼進一步優化並編譯成機器代碼,提升運行效率;
2.2 jvm虛擬機的內存區域組成
程序計數器,線程私有,指向字節碼指令;
java虛擬機棧,線程私有,主要就是描述java方法的,配合程序計數器一塊兒一步一步往下執行方法(理解爲何是棧);
本地方法棧,線程私有,跟java虛擬機棧相似,區別是它用來執行非java方法;
java堆,線程共享,這是最大的一塊虛擬機內存區域,主要就是咱們new的對象都會分配在這裏,這裏分爲新生代(Eden、Survivor一、Survivor2)和老年代;
方法區,線程共享,在HotSpot裏叫永久代(Permanent Generation),存放加載的類信息、常量、靜態變量等,static代碼塊、static變量、static方法都會存放在這裏有一個副本。爲何叫永久代,主要是對這部分的對象實例回收的效率不高,這部分對象實例存活率較高;
運行時常量池,是方法區的一部分;
直接內存,不是虛擬機內存的一部分,指申請虛擬機內存外的內存。
2.3 垃圾收集算法
怎麼樣判斷對象能夠回收?有引用計數算法和可達性分析算法。引用計數算法很簡單,給每一個對象一個引用計數器,每當有一個地方引用了它,那麼就給它計數器+1,當這個引用失效以後計數器-1,這樣作很是高效,但有一個缺陷是互相引用的對象,沒法被回收,形成內存泄露。HotSpot使用可達性分析算法,可達性分析算法從GC Roots對象出發是否可達來判斷對象是否能夠回收,GC Roots對象包括虛擬機棧引用的對象、方法區類靜態屬性引用的對象、方法區常量引用的對象、本地方法棧中引用的對象;
IBM研究指出98%的對象都是朝生夕死,故新生代中回收頻率要較高,每次能夠回收大量內存,老年代中通過兩次以上的回收仍存活,說明回收的效率不高,回收頻率能夠低一點。另外,大對象不在新生代中分配,而是直接進入老年代。
①標記-清除算法。算法的思想是首先把須要回收的對象標註出來,而後統一清除回收。實現起來很簡單,但標記和清除的效率不高,還會產生大量不連續的內存空間,影響後續爲新對象分配內存,尤爲是大對象。
②複製算法。針對標記-清除算法的問題,複製算法的思想是把內存區域均等的分紅兩塊,好比10M的內存均等分爲兩塊5M,每一個時刻只能使用一塊,第一次將新對象分配給第一塊內存,第一次GC時,先從第一塊標記仍存活對象的對象,而後統一複製到第二塊內存中,並按內存空間順序排好,第一塊內存則所有回收。第二次回收時就先從第二塊開始,循環往復。這樣作效率很高,而且內存空間能夠連續分配。但形成一個問題是原本10M的內存只能用一半,形成內存的浪費。
HotSpot在實際實現複製算法時,將內存空間劃分爲Eden和兩個Survivor,且默認Eden和Survivor的比例是8:1:1,新對象分配在Eden中,第一次回收後存活對象被複制到Survivor 1中,Eden所有清除,第二次新對象仍分配在Eden中,第二次回收時Eden和Survivor 1中存活對象被複制到Survivor 2中,Eden和Survivor 1所有清除。
這裏有一個問題:若是存活對象超過內存的10%,Survivor放不下怎麼辦?這時候就須要從老年代中進行分配擔保(Handle Promotion)。
③標記-整理算法。和新生代不一樣,在老年代中GC回收的效率不會過高,使用複製算法Survivor空間極可能是不夠的,若是將Survivor調大又浪費內存空間,這時就提出了標記-整理算法應對老年代的實際狀況。標記-整理算法內存回收時先將全部存活對象標記出來,但不進行清除,而是將存活對象都往內存的一端移動,那麼內存末端都是可回收的對象,當這些可回收對象被「擠出」內存邊界的時候,則被清除了。
因爲HotSpot中把java堆中分爲新生代、老年代,他們存活的概率不同,因此按新生代和老年代採起不一樣的算法,這就叫分代收集算法,在新生代中採起復制算法,在老年代中使用標記-清除或標記-整理算法。
2.4 垃圾收集器
上面分析了新生代、老年代應該採起怎樣的算法,HotSpot中針對實際應用場景,實現了不一樣的垃圾收集器:
①Serial收集器,複製算法,單線程,Client模式下默認新生代收集器。會有Stop The World問題;
②ParNew收集器,複製算法,多線程,新生代收集器;
③Parallel Scavenge收集器,複製算法,多線程,新生代收集器,與ParNew的區別在於它針對吞吐量設計的;
④Serial Old收集器,標記-整理算法,單線程,Client模式下默認老年代收集器;
⑤CMS收集器,標記-清除算法,多線程,老年代收集器,以下降停頓時間爲目標,只在初始標記、從新標記的時候須要Stop The World,採起併發標記和併發清除下降停頓時間;
⑥G1收集器,標記-整理算法+複製算法,多線程,新生代+老年代收集器,是JDK1.7最新的研究成果,以CMS收集器的基礎上,加上覆制算法的理念,將內存區域劃分爲多個大小相等的Region,每一個Region再分爲新生代和老年代。每次GC時根據Region回收價值優先進行回收,避免之前收集器須要進行全區域垃圾收集和回收;
3、編譯與運行
3.1 javac編譯器編譯
第一次編譯,將.java文件編譯成中間語言,輸出.Class文件,這期間主要完成語法分析和詞法分析(編譯原理)、註解處理、語義分析(解語法糖等)、生成字節碼Class文件;
3.2 解釋器
類加載進解釋器運行,類加載的過程有:加載、驗證、準備、解析、初始化;
3.3 JIT即時編譯器
解釋器監控熱點代碼爲JIT編譯器進一步編譯提供監控數據,觸發JIT編譯器將熱點代碼編譯成機器代碼;
本人知識水平有限,文章不免有紕漏之處,請不吝糾正勘誤。