shopee提前批面經(jīng)及答案
JVM字節(jié)碼文件對象的結(jié)構(gòu)
對象在堆內(nèi)存的存儲布局可分為對象頭、實例數(shù)據(jù)和對齊填充。
對象頭主要包含兩部分數(shù)據(jù):MarkWord、類型指針。MarkWord 用于存儲哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標志位、線程持有的鎖、偏向線程ID等信息。類型指針即對象指向他的類元數(shù)據(jù)指針,如果對象是一個 Java 數(shù)組,會有一塊用于記錄數(shù)組長度的數(shù)據(jù),
實例數(shù)據(jù)存儲代碼中所定義的各種類型的字段信息。
對齊填充起占位作用。HotSpot 虛擬機要求對象的起始地址必須是8的整數(shù)倍,因此需要對齊填充。
JVM運行期內(nèi)存空間,每塊的作用
線程私有的運行時數(shù)據(jù)區(qū): 程序計數(shù)器、Java 虛擬機棧、本地方法棧。
線程共享的運行時數(shù)據(jù)區(qū):Java 堆、方法區(qū)。
對象一定在堆中嗎
類(靜態(tài))變量也存儲在方法區(qū)中。
字符串常量池
運行時常量池存放常量池表,用于存放編譯器生成的各種字面量與符號引用。一般除了保存 Class 文件中描述的符號引用外,還會把符號引用翻譯的直接引用也存儲在運行時常量池。除此之外,也會存放字符串基本類型。
JDK8之前,放在方法區(qū),大小受限于方法區(qū)。JDK8將運行時常量池存放堆中。
虛擬機的類加載機制
加載:
通過全類名獲取類的二進制字節(jié)流. 將類的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。在內(nèi)存中生成類的Class對象,作為方法區(qū)數(shù)據(jù)的入口。驗證:對文件格式,元數(shù)據(jù),字節(jié)碼,符號引用等驗證正確性。
準備:在方法區(qū)內(nèi)為類變量分配內(nèi)存并設(shè)置為0值。
解析:將符號引用轉(zhuǎn)化為直接引用。
初始化:執(zhí)行類構(gòu)造器clinit方法,真正初始化。
JVM的雙親委派模型
一個類加載器收到類加載請求之后,首先判斷當前類是否被加載過。已經(jīng)被加載的類會直接返回,如果沒有被加載,首先將類加載請求轉(zhuǎn)發(fā)給父類加載器,一直轉(zhuǎn)發(fā)到啟動類加載器,只有當父類加載器無法完成時才嘗試自己加載。
加載類順序:BootstrapClassLoader->ExtensionClassLoader->AppClassLoader->CustomClassLoader 檢查類是否加載順序:CustomClassLoader->AppClassLoader->ExtensionClassLoader->BootstrapClassLoader
ArrayList和Linkedlist底層
ArrayList 使用數(shù)組實現(xiàn),是容量可變的非線程安全列表,隨機訪問快,集合擴容時會創(chuàng)建更大的數(shù)組,把原有數(shù)組復(fù)制到新數(shù)組。
LinkedList 本質(zhì)是雙向鏈表,與 ArrayList 相比插入和刪除速度更快,但隨機訪問元素很慢。
JVM垃圾收集每種算法
標記清除算法:先標記需清除的對象,之后統(tǒng)一回收。這種方法效率不高,會產(chǎn)生大量不連續(xù)的碎片。
標記整理算法:先標記存活對象,然后讓所有存活對象向一端移動,之后清理端邊界以外的內(nèi)存
標記復(fù)制算法:將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中一塊。當使用的這塊空間用完了,就將存活對象復(fù)制到另一塊,再把已使用過的內(nèi)存空間一次清理掉。
調(diào)用system.gc()一定會發(fā)生垃圾收集嗎?為什么?
調(diào)用System.gc()的時候,其實并不會馬上進行垃圾回收,只會把這次gc請求記錄下來。需配合System.runFinalization()才會進行真正回收
說一下對于樹的理解
數(shù)據(jù)結(jié)構(gòu)樹是一種由有限節(jié)點組成的層次關(guān)系的集合。其特點如下:
- 每個節(jié)點有零個或多個子節(jié)點;
- 只有一個節(jié)點沒有父節(jié)點,該節(jié)點稱為根節(jié)點;
- 除根節(jié)點外,每個節(jié)點有且只有一個父節(jié)點;
簡述二叉樹
二叉樹是n個有限元素的集合,該集合或者為空、或者由一個稱為根(root)的元素及兩個不相交的、被分別稱為左子樹和右子樹的二叉樹組成。
簡述二叉查找樹(二叉搜索樹)
- 二叉查找樹的左子樹若不為空,則左子樹上所有結(jié)點的值均小于它的根結(jié)點的值;
- 二叉查找樹的右子樹若不為空,則右子樹上所有結(jié)點的值均大于它的根結(jié)點的值;
- 二叉查找樹的左、右子樹也分別為二叉查找樹;
- 沒有鍵值相等的結(jié)點。
簡述紅黑樹
紅黑樹本身是有2-3樹發(fā)展而來,紅黑樹是保持黑平衡的二叉樹,其查找會比AVL樹慢一點,添加和刪除元素會比AVL樹快一點。增刪改查統(tǒng)計性能上講,紅黑樹更優(yōu)。紅黑樹主要特征是在每個節(jié)點上增加一個屬性表示節(jié)點顏色,可以紅色或黑色。紅黑樹和 AVL 樹類似,都是在進行插入和刪除時通過旋轉(zhuǎn)保持自身平衡,從而獲得較高的查找性能。紅黑樹保證從根節(jié)點到葉尾的最長路徑不超過最短路徑的 2 倍,所以最差時間復(fù)雜度是 O(logn)。紅黑樹通過重新著色和左右旋轉(zhuǎn),更加高效地完成了插入和刪除之后的自平衡調(diào)整。
設(shè)計模式的幾大基本原則
開放封閉原則:對擴展開放,對修改關(guān)閉。在程序需要進行拓展的時候,不能去修改原有的代碼,實現(xiàn)一個熱插拔的效果。
單一職責原則:一個類、接口或方法只負責一個職責,降低代碼復(fù)雜度以及變更引起的風險。
依賴倒置原則:針對接口編程,依賴于抽象類或接口而不依賴于具體實現(xiàn)類。
接口隔離原則:將不同功能定義在不同接口中實現(xiàn)接口隔離。
里氏替換原則:任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。
迪米特原則:每個模塊對其他模塊都要盡可能少地了解和依賴,降低代碼耦合度。
合成復(fù)用原則:盡量使用組合(has-a)/聚合(contains-a)而不是繼承(is-a)達到軟件復(fù)用的目的。
說一下你理解的幾種設(shè)計模式
簡單工廠模式指由一個工廠對象來創(chuàng)建實例,適用于工廠類負責創(chuàng)建對象較少的情況。例子:Spring 中的 BeanFactory 使用簡單工廠模式,產(chǎn)生 Bean 對象。
代理模式為其他對象提供一種代理以控制對這個對象的訪問。優(yōu)點是可以增強目標對象的功能,降低代碼耦合度,擴展性好。缺點是在客戶端和目標對象之間增加代理對象會導(dǎo)致請求處理速度變慢,增加系統(tǒng)復(fù)雜度。
適配器模式將一個接口轉(zhuǎn)換成客戶希望的另一個接口,使接口不兼容的那些類可以一起工作。
MYSQL的事務(wù)隔離機制
讀未提交:一個事務(wù)還沒提交,它做的變更就能被別的事務(wù)看到。讀提交:一個事務(wù)提交后,它做的變更才能被別的事務(wù)看到??芍貜?fù)讀:一個事務(wù)執(zhí)行過程中看到的數(shù)據(jù)總是和事務(wù)啟動時看到的數(shù)據(jù)是一致的。在這個級別下事務(wù)未提交,做出的變更其它事務(wù)也看不到。串行化:對于同一行記錄進行讀寫會分別加讀寫鎖,當發(fā)生讀寫鎖沖突,后面執(zhí)行的事務(wù)需等前面執(zhí)行的事務(wù)完成才能繼續(xù)執(zhí)行。
MYSQL的A C I D怎樣實現(xiàn)的
利用undo log保障原子性。該log保存了事務(wù)發(fā)生之前的數(shù)據(jù)的一個版本,可以用于回滾,從而保證事務(wù)原子性。
利用redo log保證事務(wù)的持久性,該log關(guān)注于事務(wù)的恢復(fù).在重啟mysql服務(wù)的時候,根據(jù)redo log進行重做,從而使事務(wù)有持久性。
利用undo log+redo log保障一致性。事務(wù)中的執(zhí)行需要redo log,如果執(zhí)行失敗,需要undo log 回滾。
MVCC原理
MVCC為多版本并發(fā)控制,即同一條記錄在系統(tǒng)中存在多個版本。其存在目的是在保證數(shù)據(jù)一致性的前提下提供一種高并發(fā)的訪問性能。對數(shù)據(jù)讀寫在不加讀寫鎖的情況下實現(xiàn)互不干擾,從而實現(xiàn)數(shù)據(jù)庫的隔離性,在事務(wù)隔離級別為讀提交和可重復(fù)讀中使用到。
在InnoDB中,事務(wù)在開始前會向事務(wù)系統(tǒng)申請一個事務(wù)ID,該ID是按申請順序嚴格遞增的。每行數(shù)據(jù)具有多個版本,每次事務(wù)更新數(shù)據(jù)都會生成新的數(shù)據(jù)版本,而不會直接覆蓋舊的數(shù)據(jù)版本。數(shù)據(jù)的行結(jié)構(gòu)中包含多個信息字段。其中實現(xiàn)MVCC的主要涉及最近更改該行數(shù)據(jù)的事務(wù)ID(DBTRXID)和可以找到歷史數(shù)據(jù)版本的指針(DBROLLPTR)。InnoDB在每個事務(wù)開啟瞬間會為其構(gòu)造一個記錄當前已經(jīng)開啟但未提交的事務(wù)ID的視圖數(shù)組。通過比較鏈表中的事務(wù)ID與該行數(shù)據(jù)的值與對應(yīng)的DBTRXID,并通過DBROLLPTR找到歷史數(shù)據(jù)的值以及對應(yīng)的DBTRXID來決定當前版本的數(shù)據(jù)是否應(yīng)該被當前事務(wù)所見。最終實現(xiàn)在不加鎖的情況下保證數(shù)據(jù)的一致性
簡述redo_log undo_log
redo log: 存儲引擎級別的log(InnoDB有,MyISAM沒有),該log關(guān)注于事務(wù)的恢復(fù).在重啟mysql服務(wù)的時候,根據(jù)redo log進行重做,從而使事務(wù)有持久性。
undo log:是存儲引擎級別的log(InnoDB有,MyISAM沒有)保證數(shù)據(jù)的原子性,該log保存了事務(wù)發(fā)生之前的數(shù)據(jù)的一個版本,可以用于回滾,是MVCC的重要實現(xiàn)方法之一。
簡述Redis的淘汰機制
- noeviction:默認禁止驅(qū)逐數(shù)據(jù)。內(nèi)存不夠使用時,對申請內(nèi)存的命令報錯。
- volatile-lru:從設(shè)置了過期時間的數(shù)據(jù)集中淘汰最近沒使用的數(shù)據(jù)。
- volatile-ttl:從設(shè)置了過期時間的數(shù)據(jù)集中淘汰即將要過期的數(shù)據(jù)。
- volatile-random:從設(shè)置了過期時間的數(shù)據(jù)中隨機淘汰數(shù)據(jù)。
- allkeys-lru:淘汰最近沒使用的數(shù)據(jù)。
- allkeys-random:隨機淘汰數(shù)據(jù)。
簡述Redis過期策略
- 定期刪除,redis默認是每100ms就隨機抽取一些設(shè)置了過期時間的key,并檢查其是否過期,如果過期就刪除。因此該刪除策略并不會刪除所有的過期key。
- 惰性刪除,在客戶端需要獲取某個key時,redis將首先進行檢查,若該key設(shè)置了過期時間并已經(jīng)過期就會刪除。
實際上redis結(jié)合上述兩種手段結(jié)合起來,保證刪除過期的key。
面經(jīng)鏈接:http://fangfengwang8.cn/discuss/678130