一、在JDK1.6(HotSpot虛擬機)及以前,運行時常量池(屬於方法區的一部分)是永久代的,而在JDK1.7以後運行時常量池(裏面用於存放編譯期生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時常量池當中存放)已經從永久代(Permanent Generation)移出。(問:那麼方法區其餘部分有沒有移出永久代?)java
二、關於String.intern()方法,在1.6及之前會把首次遇到的字符串實例複製到永久代當中去,返回的也是永久代中這個字符串實例的引用;在1.7以後intern()實現不會再複製實例,只是在常量池中記錄首次出現的實例引用,返回的就是那個實例引用。算法
三、Java的JVM並非經過引用計數來進行GC,由於它很難解決對象之間相互循環引用的問題,譬如:安全
public class Test{ public Object instance = null; public static void testGC(){ Test objA = new Test(); Test objB = new Test(); objA.instance = objB; objB.instance = objA; objA=null; objB=null; //假設在這行發生了GC,objA 和 objB可否被回收? System.gc(); } }
雖然這兩個對象都已經不可能再被訪問了,可是因爲他們相互引用這對方,致使它們的引用計數都不爲0,因而引用計數算法沒法通知GC收集器回收它們。併發
四、Java採用可達性分析來判斷對象是否存活,通常經過」GC ROOTS「的對象來做爲起始點,通常可做爲「GC roots」的對象包括下面4種:優化
1)虛擬機棧(棧幀中的本地變量表)中引用的對象。spa
2)方法區中類靜態屬性引用的對象。線程
3)方法區中常量引用的對象。code
4)本地方法棧中JNI(即通常說的Native方法)引用的對象。對象
五、JDK1.2以後Java對引用的概念進行了擴充,分爲四種,引用強度依次從強到弱爲強引用>軟引用>弱引用>虛引用blog
強引用是普通的相似 Object obj = new Object()的對象引用
軟引用(經過SoftReference類來實現)用來描述一些還有用但不是必須的對象,當發生內存溢出異常以前,將會把這一類對象列入回收範圍之中進行第二次回收,若是此次回收以後仍是不夠,就報內存溢出異常。
弱引用(WeakReference類來實現)也是用來描述非必須對象,但它的強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發生以前
虛引用(PhantomReference)最弱的一種引用關係,沒法經過虛引用來取得一個對象實例,通常爲對象設置虛引用關聯的惟一目的就是能在這個對象被收集器回收的時候收到一個系統通知。
六、Class文件當中的一些數據項目:
常量池容量計數值(constant_pool_count),用於表示常量池中常量的數值。須要注意的是這裏容量計數是從1開始的,由於0有特別用途,好比0x0016表示十進制的22,這就表明常量池中有21項常量,索引範圍爲1~21.
常量池中主要存放兩大類常量:字面量(如文本字符串,聲明爲final的常量值) 和 符號引用 (屬於編譯原理方面的概念,包括三類常量 見P168)
七、類從被加載到虛擬機內存到卸載出內存爲止,整個生命週期包括哪些階段?
一共包括7個階段。加載->驗證->準備->解析->初始化->使用->卸載。其中驗證、準備、解析3個部分統稱爲鏈接。
須要注意的是,加載(Loading)是類加載(Class Loading)過程的一個階段,別混淆了兩個概念。類加載過程包括上述的前5個過程。
驗證階段大體上會完成4個階段的驗證動做:文件格式驗證、元數據驗證、字節碼驗證、符號引用驗證。
八、使用volatile修飾的變量在併發下的運算必定是安全的嗎?
因爲java裏面的運算並不是原子操做,致使volatile變量的運算在併發下同樣是不安全的。因爲volatile變量只能保證可見性,因此只有知足如下兩條規則的運算場景才能夠不用鎖就能保證原子性。
1)運算結果並不依賴變量的當前值,或者可以確保只有單一的線程修改變量的值。
2)變量不須要與其餘的狀態變量共同參與不變約束。
volatile的可見性是經過Java內存模型對volatile變量定義的特殊規則,每次使用前都要read、load,每次用完都要store、write相關聯,必須連續一塊兒出現。
九、線程的實現通常有三種:內核線程實現(包括高級接口——輕量級進程)、用戶線程實現、用戶線程實現加輕量級進程混合實現
內核線程實現優勢:即便有一個輕量級進程在系統調用中阻塞了,也不會影響整個進程繼續工做
缺點:系統調用代價比較高,須要在兩種態當中來回切換,因爲每一個LWP都須要一個內核線程的支持,所以會消耗內核資源,支持的數量有限。
用戶線程實現優勢:操做快,消耗少,支持規模更大的線程數量
缺點:阻塞問題如何處理,多處理器系統中如何將線程映射到其餘處理器上,這類問題解決起來異常困難
混合實現:
十、線程調度方式主要分爲兩種:協同式和搶佔式。
十一、自旋鎖(JVM層面的鎖優化技術):在許多應用上,共享數據的鎖定狀態只會持續很短的一段時間,爲了這段時間去掛起和恢復線程並不值得,因此若是物理機器有一個以上的處理器,能讓兩個或以上的線程同時並行執行,咱們就可讓後面請求所的那個線程「稍等一下」,看看持有鎖的線程是否很快就釋放鎖,這種讓線程採用忙循環(自旋),這項技術就是所謂的自旋鎖。
優勢:避免線程切換的開銷(內核態與用戶態的上下文切換)
缺點:佔用處理器的時間,對處理器數量有要求。
十二、Java語言定義的GC Roots對象包括:
1)虛擬機棧(棧幀中的本地變量表)中引用的對象。
2)方法區中靜態屬性引用的對象
3)方法區中常量引用的對象
4)本地方法棧中JNI引用的對象