本文這個只是我本身整理的面試中多面到的一些JVM方面的知識點,就這樣看它們都是孤立的,我是看《深刻Java虛擬機》以及極客時間一個JVM系列的文章,才把這些概念給貫通的。java
好比一個知識點:垃圾回收分Minor GC、Full GC。Minor發生在新生代,新生代分Eden、Survivor,而Survivor又分 From Survivor、To Survivor。新生代採用的是Copy機制的垃圾回收算法,經過空間換時間,它是怎麼換的呢?To Survivor是一塊空的內存,垃圾回收時,會把Eden、From Survivor中的可達的(區別堆外不可達)對象搬到 To Survivor中去,而後清除Eden、Form Survivor,整個過程接受後,交換From跟To,這期間有可能把對象從Eden、From搬去To的時候,To內存不足則須要借用老生代的內存,這就是所謂的內存擔保。面試
程序計數器:每一個線程執行程序指令的行號算法
虛擬機棧:存放每一個方法的棧幀,幀的入棧跟出棧就是方法執行的過程緩存
本地方法棧:Native方法的棧安全
Java堆:保存Java對象的地方,細分爲 Eden區, From Survivor空間, To Survivor空間(線程共享)多線程
方法區:線程共享,存放已經被虛擬機加載進來的類信息,常量、靜態變量,JIT編譯後的數據代碼。java的class文件首先進入的到方法區裏面去。app
方法區的一部分。優化
強引用:只要強引用還在,引用的對象永遠不會被回收線程
軟引用: 發生內存溢出以前會清除orm
弱引用:垃圾回收的時候會收走
虛引用:對象生命週期不會受到它影響,只是在被回收掉的時候,收到通知。
safePoint、安全區域 。(不操做內存的寫,不跟主存打交道) STW(stop the world)
eden, survior中調用 Minor GC,之因此沒有用STW,添加了統計老生代到 新生代數據引用的卡表(髒位)
新生代(eden + from + to)TLAB(Thread Local Allocation Buffers)因爲to Survior的空間不夠,找老年代作內存擔保。
當經歷過幾回 從from 到 to過程後依舊活着的對象就能夠進入到 老生代中去了。
Serial (單線程,新生代,copy算法)
Parallel New(多線程,新生代,copy算法,時間優先)
Parallel Scavenge(多線程,新生代,copy算法,吞吐量優先)
Serial Old(單線程,老生代, 標記清除)
Parallel Old(多線程,老生代, 標記清除)
CMS:垃圾收集器跟應用並行(多線程,老生代, 標記清除)分兩次清理,第一次清理的時候,工做線程跟垃圾線程並行,第二次STW。(Java 9 被廢除)
G1 (新生代 + 老生代)
熱點方法,循環熱點
C、C++屬於靜態編譯,運行時候不會。java屬於動態編譯,虛方法動態分配,激進優化等使之更完全,可是佔用CPU。
優化方式:
內聯優化(省去了方法的加載,壓棧等。詭異的TR1圖)
逃逸分析(對象沒有被方法外引用的時候,直接到接近CPU的棧上分配存儲空間。方法僅被一個線程調用到的時候,去掉同步鎖。)
指令集(Compare And Sweep, Compare and Set),???
循環優化、向量優化
偏向鎖 (當第一次進入到同步代碼塊的時候,不上鎖,修改對象頭中的Mark word,線程的ID等信息,經過CAS指令,全程只有一個線程,因此記錄它偏向它,偏向鎖)
輕量級鎖 (只有一個線程,把線程上鎖記錄加入到 對象頭中去,採用CAS,再也不是第一個線程,而是另外的線程不一樣時間段執行同步代碼塊,有偏向鎖到 輕量級鎖)
重量級鎖(一個線程在執行,另外一個線程來競爭。輕量級鎖 鎖膨脹爲重量級鎖)等待的線程沒有直接去wait,而是運行空指令處於就緒狀態,等待運行中的線程釋放鎖,而後本身拿取,這樣的叫自旋鎖。爲何要添加這個自選狀態呢?
當線程一旦進入到wait後,就統一交由CPU進行管理 + 調度,轉爲內核態,到時候喚醒運行變爲用戶態,這個過程的切換有不少資源的 消耗(內存的拷貝複製等),在這裏運行空指令消耗可能比這個切換更加省CPU。可是對於其餘鎖而言就失去公平性了。
這樣相比而言,協程有本身管理、調度部區份內核態、用戶態,資源開支比較小,是現代語言(Kotlin等)中經常使用的技術。(搶佔式調度、協同式)
synchronized(monitor, monitorenter, monitorexit)
ReentrantLock(重入鎖), NewCondtion