面試題總結(jié)

1.什么情況下會發(fā)生棧內(nèi)存溢出纵潦。

  • 棧是線程私有的,他的生命周期與線程相同垃环,每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀邀层,用來存儲局部變量表,操作數(shù)棧遂庄,動態(tài)鏈接寥院,方法出口等信息。局部變量表又包含基本數(shù)據(jù)類型涛目,對象引用類型
    如果線程請求的棧深度大于虛擬機(jī)所允許的最大深度秸谢,將拋出StackOverflowError異常,方法遞歸調(diào)用產(chǎn)生這種結(jié)果霹肝。
    如果Java虛擬機(jī)椆捞悖可以動態(tài)擴(kuò)展,并且擴(kuò)展的動作已經(jīng)嘗試過沫换,但是無法申請到足夠的內(nèi)存去完成擴(kuò)展臭蚁,或者在新建立線程的時候沒有足夠的內(nèi)存去創(chuàng)建對應(yīng)的虛擬機(jī)棧,那么Java虛擬機(jī)將拋出一個OutOfMemory 異常讯赏。(線程啟動過多)
    參數(shù) -Xss 去調(diào)整JVM棧的大小

2.詳解JVM內(nèi)存模型垮兑。

image.png
  • 程序計數(shù)器(線程私有)

程序計數(shù)器是一塊很小的內(nèi)存空間,它是線程私有的漱挎,可以認(rèn)作為當(dāng)前線程的行號指示器系枪。
我們知道對于一個處理器(如果是多核cpu那就是一核),在一個確定的時刻都只會執(zhí)行一條線程中的指令识樱,一條線程中有多個指令嗤无,為了線程切換可以恢復(fù)到正確執(zhí)行位置震束,每個線程都需有獨立的一個程序計數(shù)器,不同線程之間的程序計數(shù)器互不影響当犯,獨立存儲垢村。
注意:如果線程執(zhí)行的是個java方法,那么計數(shù)器記錄虛擬機(jī)字節(jié)碼指令的地址嚎卫。如果為native【底層方法】嘉栓,那么計數(shù)器為空。這塊內(nèi)存區(qū)域是虛擬機(jī)規(guī)范中唯一沒有OutOfMemoryError的區(qū)域拓诸。

  • Java棧(虛擬機(jī)棧 線程私有)

同計數(shù)器也為線程私有侵佃,生命周期與相同,就是我們平時說的棧奠支,棧描述的是Java
方法執(zhí)行的內(nèi)存模型馋辈。每個方法被執(zhí)行的時候都會創(chuàng)建一個棧幀用于存儲局部變量表,操作棧倍谜,動態(tài)鏈接迈螟,方法出口等信息。每一個方法被調(diào)用的過程就對應(yīng)一個棧幀在虛擬機(jī)棧中從入棧到出棧的過程尔崔。

  • 堆(線程共享)

對于大多數(shù)應(yīng)用來說答毫,堆是java虛擬機(jī)管理內(nèi)存最大的一塊內(nèi)存區(qū)域,因為堆存放的對象是線程共享的季春,所以多線程的時候也需要同步機(jī)制洗搂。創(chuàng)建的對象和數(shù)組都保存在 Java 堆內(nèi)存中,也是垃圾收集器進(jìn)行垃圾收集的最重要的內(nèi)存區(qū)域载弄。由于現(xiàn)代 VM 采用分代收集算法, 因此 Java 堆從 GC 的角度還可以
細(xì)分為: 新生代( Eden 區(qū) 耘拇、 From Survivor 區(qū) 和 To Survivor 區(qū) )和老年代。

  • 本地方法區(qū)(私有)

方法區(qū)同堆一樣侦锯,是所有線程共享的內(nèi)存區(qū)域驼鞭,為了區(qū)分堆秦驯,又被稱為非堆.
用于存儲已被虛擬機(jī)加載的類信息尺碰、常量、靜態(tài)變量译隘,如static修飾的變量加載類的時候就被加載到方法區(qū)中亲桥。

3.springmvc工作流程

  • springmvc請求過程
  • 組件說明
    1.DispatcherServlet:前端控制器。用戶請求到達(dá)前端控制器固耘,它就相當(dāng)于mvc模式中的c题篷,dispatcherServlet是整個流程控制的中心,由它調(diào)用其它組件處理用戶的請求厅目,dispatcherServlet的存在降低了組件之間的耦合性,系統(tǒng)擴(kuò)展性提高番枚。由框架實現(xiàn)
    2.HandlerMapping:處理器映射器法严。HandlerMapping負(fù)責(zé)根據(jù)用戶請求的url找到Handler即處理器,springmvc提供了不同的映射器實現(xiàn)不同的映射方式葫笼,根據(jù)一定的規(guī)則去查找,例如:xml配置方式深啤,實現(xiàn)接口方式,注解方式等路星。由框架實現(xiàn)
    3.Handler:處理器溯街。Handler 是繼DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler對具體的用戶請求進(jìn)行處理洋丐。由于Handler涉及到具體的用戶業(yè)務(wù)請求呈昔,所以一般情況需要程序員根據(jù)業(yè)務(wù)需求開發(fā)Handler。
    4.HandlAdapter:處理器適配器友绝。通過HandlerAdapter對處理器進(jìn)行執(zhí)行堤尾,這是適配器模式的應(yīng)用,通過擴(kuò)展適配器可以對更多類型的處理器進(jìn)行執(zhí)行迁客。由框架實現(xiàn)哀峻。
    5.ModelAndView是springmvc的封裝對象,將model和view封裝在一起哲泊。
    6.ViewResolver:視圖解析器剩蟀。ViewResolver負(fù)責(zé)將處理結(jié)果生成View視圖,ViewResolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址切威,再生成View視圖對象育特,最后對View進(jìn)行渲染將處理結(jié)果通過頁面展示給用戶。
    7View:是springmvc的封裝對象先朦,是一個接口, springmvc框架提供了很多的View視圖類型缰冤,包括:jspview,pdfview,jstlView喳魏、freemarkerView棉浸、pdfView等。一般情況下需要通過頁面標(biāo)簽或頁面模版技術(shù)將模型數(shù)據(jù)通過頁面展示給用戶刺彩,需要由程序員根據(jù)業(yè)務(wù)需求開發(fā)具體的頁面迷郑。
  • 執(zhí)行流程
    SpringMVC執(zhí)行流程:
    1.用戶發(fā)送請求至前端控制器DispatcherServlet
    2.DispatcherServlet收到請求調(diào)用處理器映射器HandlerMapping。
    3.處理器映射器根據(jù)請求url找到具體的處理器创倔,生成處理器執(zhí)行鏈HandlerExecutionChain(包括處理器對象和處理器攔截器)一并返回給DispatcherServlet嗡害。
    4.DispatcherServlet根據(jù)處理器Handler獲取處理器適配器HandlerAdapter執(zhí)行HandlerAdapter處理一系列的操作,如:參數(shù)封裝畦攘,數(shù)據(jù)格式轉(zhuǎn)換霸妹,數(shù)據(jù)驗證等操作
    5.執(zhí)行處理器Handler(Controller,也叫頁面控制器)知押。
    6.Handler執(zhí)行完成返回ModelAndView
    7.HandlerAdapter將Handler執(zhí)行結(jié)果ModelAndView返回到DispatcherServlet
    8.DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
    9.ViewReslover解析后返回具體View
    10.DispatcherServlet對View進(jìn)行渲染視圖(即將模型數(shù)據(jù)model填充至視圖中)叹螟。
    11.DispatcherServlet響應(yīng)用戶鹃骂。

4.int i = 1 存放在哪里?

全局變量i,他是存放在java堆中罢绽。因為它不是靜態(tài)的變量偎漫,不會獨立于類的實例而存在,而該類實例化之后有缆,放在堆中象踊,當(dāng)然也包含了它的屬性i。
如果在方法中定義了int i = 0;則在局部變量表創(chuàng)建了兩個對象:引用i和0棚壁。 這兩個對象都是線程私有(安全)的杯矩。 比如定義了int[] is = new int[10]. 定義了兩個對象,一個是is引用袖外,放在局部變量表中史隆,一個是長度為10的數(shù)組,放在堆中曼验,這個數(shù)組泌射,只能通過is來訪問,方法結(jié)束后出棧鬓照,is被銷毀熔酷,根據(jù)java的根搜索算法,判斷數(shù)組不可達(dá)豺裆,就將它銷毀了拒秘。
成員變量 int a = 1; a 存放在方法區(qū),1存放在堆內(nèi)存臭猜,a指向該內(nèi)存
局部變量 int a = 1;a 存放在方法區(qū)躺酒, 1存放在棧內(nèi)存,a指向該變量

5. springboot注入配置文件有哪幾種方式

@ConfigurationProperties(prefix = "person") 注入yml文件
@Value 需要使用spel語法
@PropertySource 僅支持.properties文件不支持yml文件

6.給你一個ThreadPoolExcuter 現(xiàn)在我們給他一些構(gòu)造參數(shù)蔑歌,核心線程數(shù)10 羹应,最大線程數(shù)100,隊列長度1024次屠,過期時間5秒园匹,還有拒絕策略。現(xiàn)在我開2000個任務(wù)帅矗,他會怎么執(zhí)行

答:當(dāng)線程數(shù)量小于核心線程數(shù)量偎肃,線程池會創(chuàng)建線程來執(zhí)行任務(wù)煞烫,如果超過了核心線程數(shù)量浑此,線程池會把任務(wù)放入隊列,如果隊列滿了滞详,線程池會繼續(xù)創(chuàng)建線程直到線程數(shù)量=最大線程數(shù)量凛俱。如果此時還有任務(wù)要執(zhí)行紊馏,線程池會執(zhí)行拒絕策略。線程空閑時間超過5秒的時候,他會被銷毀.
線程池的拒絕策略
(1)ThreadPoolExecutor.AbortPolicy 丟棄任務(wù)蒲犬,并拋出RejectedExecutionException 異常朱监。
(2)ThreadPoolExecutor.CallerRunsPolicy:該任務(wù)被線程池拒絕,由調(diào)用 execute方法的線程執(zhí)行該任務(wù)原叮。
(3)ThreadPoolExecutor.DiscardOldestPolicy : 拋棄隊列最前面的任務(wù)赫编,然后重新嘗試執(zhí)行任務(wù)。
(4)ThreadPoolExecutor.DiscardPolicy奋隶,丟棄任務(wù)接谨,不過也不拋出異常诫欠。

7.maven整個生命周期

驗證(validate)
編譯源碼(compile)
編譯測試源碼(test-compile)
單元測試(test)
打包(package)
安裝至本地倉庫(install)
復(fù)制到遠(yuǎn)程倉庫(deploy)

8. 解決maven jar沖突問題

  • 1.MAVEN項目運(yùn)行中如果報如下錯誤:
    Caused by:java.lang.NoSuchMethodError
    Caused by: java.lang.ClassNotFoundException
  • 2.jar包沖突原理
    A->B->C->D1(log 15.0):A中包含對B的依賴,B中包含對C的依賴,C中包含對D1的依賴堕阔,假設(shè)是D1是日志jar包,version為15.0
    E->F->D2(log 16.0):E中包含對F的依賴轮洋,F(xiàn)包含對D2的依賴车要,假設(shè)是D2是同一個日志jar包,version為16.0

9. 死鎖產(chǎn)生原因如何防止死鎖

Java發(fā)生死鎖的根本原因是:
死鎖是因為多線程訪問共享資源萍聊,由于訪問的順序不當(dāng)所造成的问芬,在申請鎖時發(fā)生了交叉閉環(huán)申請。即線程在獲得了鎖A并且沒有釋放的情況下去申請鎖B寿桨,這時愈诚,另一個線程已經(jīng)獲得了鎖B,在釋放鎖B之前又要先獲得鎖A牛隅,因此閉環(huán)發(fā)生炕柔,陷入死鎖循環(huán)。
防止死鎖:
1)盡量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock媒佣、ReentrantReadWriteLock)匕累,設(shè)置超時時間,超時可以退出防止死鎖默伍。
2)盡量使用java.util.concurrent(jdk 1.5以上)包的并發(fā)類代替手寫控制并發(fā)欢嘿,比較常用的是ConcurrentHashMap、ConcurrentLinkedQueue也糊、AtomicBoolean等等炼蹦,實際應(yīng)用中java.util.concurrent.atomic十分有用,簡單方便且效率比使用Lock更高
3)盡量降低鎖的使用粒度狸剃,盡量不要幾個功能用同一把鎖
4)盡量減少同步的代碼塊

10.java中同步和并發(fā)的概念

  • 1.同步的概念
    synchronize從英譯過來是"是同時發(fā)生"掐隐。
    但其真正的含義確實截然相反的。線程同步的真實意思,其實是“排隊”:幾個線程之間要排隊虑省,一個一個對共享資源進(jìn)行操作匿刮,而不是同時進(jìn)行操作。線程同步的目的就是讓各個線程去排隊使用資源探颈,而不是讓線程同時去使用資源熟丸。
  • 并發(fā)的概念

11.線程安全和線程不安全的集合

1.線程安全集合
Vector:就比Arraylist多了個同步化機(jī)制(線程安全)。
Hashtable:就比Hashmap多了個線程安全伪节。
ConcurrentHashMap:是一種高效但是線程安全的集合光羞。
Stack:棧,也是線程安全的怀大,繼承于Vector狞山。
2.線程不安全集合
ArrayList、LinkedList叉寂、HashSet萍启、TreeSet、HashMap屏鳍、TreeMap等都是線程不安全的勘纯。值得注意的是:為了保證集合是線程安全的,相應(yīng)的效率也比較低钓瞭;線程不安全的集合效率相對會高一些驳遵。

12.innodb索引結(jié)構(gòu)為什么是樹結(jié)構(gòu),不是hash結(jié)構(gòu)山涡。

hash索引堤结,時間復(fù)雜度為O(1),平衡二叉樹的時間復(fù)雜度為O(lg(n))鸭丛。但是由于sql查詢數(shù)據(jù)竞穷,很多都是范圍查詢,而樹是有序的鳞溉,hash是無序的瘾带,hash定位不到范圍數(shù)據(jù),所以索引結(jié)構(gòu)是樹熟菲,而不用hash結(jié)構(gòu)看政。
此外,支持hash索引的引擎有:


image.png

innodb自適應(yīng)hash索引抄罕,并不是和普通b+索引一樣允蚣,我們手動指定哪一行創(chuàng)建還是不創(chuàng)建,而是innodb引擎會監(jiān)控二級索引的訪問頻率呆贿,如果頻率太高嚷兔,則自動創(chuàng)建這個二級索引的hash索引,便于下次查找這個數(shù)據(jù)的時候,不需要通過b+樹定位這個索引谴垫,而是直接hash找到這個索引章母。
當(dāng)然母蛛,可以關(guān)閉innodb_adaptive_hash_index 這個變量來關(guān)閉自適應(yīng)hash索引翩剪。

13.mysql的索引結(jié)果為什么是B+樹

b+樹和b樹的區(qū)別是
b+樹 非葉子節(jié)點不存儲記錄,記錄都是存儲在葉子節(jié)點上彩郊。2前弯、葉子節(jié)點之間有鏈表關(guān)聯(lián)。
這樣秫逝,1恕出、在范圍查找的時候,直接找到最大违帆,最小的值浙巫,然后進(jìn)行鏈表遍歷就能找到所有數(shù)據(jù),不需要再進(jìn)行樹遍歷刷后。2的畴、非葉子節(jié)點存儲pk,葉子節(jié)點存儲記錄尝胆,記錄之間存儲的會更加緊密丧裁,遍歷pk的時候,讀取一頁數(shù)據(jù)進(jìn)內(nèi)存含衔,這頁數(shù)據(jù)都是pk煎娇,而沒有實際的記錄,所以查找會更快贪染。

14.jvm優(yōu)化

1)年輕代(Young Gen):年輕代主要存放新創(chuàng)建的對象缓呛,內(nèi)存大小相對會比較小,垃圾回收會比較頻繁杭隙。年輕代分成1個Eden Space和2個Suvivor Space(命名為A和B)强经。當(dāng)對象在堆創(chuàng)建時,將進(jìn)入年輕代的Eden Space寺渗。垃圾回收器進(jìn)行垃圾回收時匿情,掃描Eden Space和A Suvivor Space,如果對象仍然存活信殊,則復(fù)制到B Suvivor Space炬称,如果B Suvivor Space已經(jīng)滿,則復(fù)制到Old Gen涡拘。同時玲躯,在掃描Suvivor Space時,如果對象已經(jīng)經(jīng)過了幾次的掃描仍然存活,JVM認(rèn)為其為一個持久化對象跷车,則將其移到Old Gen棘利。掃描完畢后,JVM將Eden Space和A Suvivor Space清空朽缴,然后交換A和B的角色(即下次垃圾回收時會掃描Eden Space和B Suvivor Space善玫。這么做主要是為了減少內(nèi)存碎片的產(chǎn)生。
我們可以看到:Young Gen垃圾回收時密强,采用將存活對象復(fù)制到到空的Suvivor Space的方式來確保盡量不存在內(nèi)存碎片茅郎,采用空間換時間的方式來加速內(nèi)存中不再被持有的對象盡快能夠得到回收。
2)年老代(Tenured Gen):年老代主要存放JVM認(rèn)為生命周期比較長的對象(經(jīng)過幾次的Young Gen的垃圾回收后仍然存在)或渤,內(nèi)存大小相對會比較大系冗,垃圾回收也相對沒有那么頻繁(譬如可能幾個小時一次)。年老代主要采用壓縮的方式來避免內(nèi)存碎片(將存活對象移動到內(nèi)存片的一邊薪鹦,也就是內(nèi)存整理)掌敬。當(dāng)然,有些垃圾回收器(譬如CMS垃圾回收器)出于效率的原因池磁,可能會不進(jìn)行壓縮奔害。
3)持久代(Perm Gen):持久代主要存放類定義、字節(jié)碼和常量等很少會變更的信息框仔。
分區(qū)的目的:新生區(qū)由于對象產(chǎn)生的比較多并且大都是朝生夕滅的舀武,所以直接采用復(fù)制算法。而養(yǎng)老區(qū)生命力很強(qiáng)离斩,則采用標(biāo)記-清理算法银舱,針對不同情況使用不同算法。
非heap區(qū)域中Perm Gen中放著類跛梗、方法的定義寻馏,JVM Stack區(qū)域放著方法參數(shù)、局域變量等的引用核偿,方法執(zhí)行順序按照棧的先入后出方式诚欠。

15.分代收集算法

  • 1.GC的分類
    Minor GC 采用復(fù)制算法
    Full GC 標(biāo)記清除算法
  • 2.年輕代:盡可能快速地收集掉那些生命周期短的對象
    Eden區(qū)
    兩個Survivor區(qū)


    image.png

    -> 3.年輕代垃圾回收過程演示
    (1)假設(shè)Eden區(qū)可存放四個對象,Survivor區(qū)可以存放3個對象


    image.png

    (2)假設(shè)Eden區(qū)被擠滿漾岳,則觸發(fā)一次Minor GC,此時如果有對象存活轰绵,則復(fù)制一份到Survivor區(qū)域中(此時S0我們成為from區(qū)域,S1為to區(qū)域)
    image.png

    (3)清理所有使用過的Eden區(qū)尼荆,并設(shè)置存活的對象年齡為1
    image.png

    (4)假設(shè)Eden區(qū)再次被填滿左腔,又會觸發(fā)一次Minor GC。會將Eden區(qū)存活的對象與S0中的對象拷貝到S1中捅儒,同時對這些對象的年齡分別+1液样。此時S0從from區(qū)變成to區(qū)振亮,S1從to區(qū)變成from區(qū)


    image.png

    (5)拷貝完成后Eden與S0均會被清空,這樣便完成第二次Minor GC
    image.png

    (6)假設(shè)Eden區(qū)又滿了鞭莽,此時觸發(fā)第三次Minor GC
    image.png

    會將Eden區(qū)存活的對象與S1中的對象拷貝到S0中坊秸,同時對這些對象的年齡分別+1
    image.png

    再次清空Eden與S1中的 對象
    image.png

    (7)周而復(fù)始,熬過一次Minor GC澎怒,年齡加一褒搔,默認(rèn)年齡到達(dá)15時進(jìn)入老年代。
  • 4.對象如何晉升老年代
    經(jīng)歷一定的Minor GC次數(shù)依然存活的對象
    Survivor區(qū)中存放不下的對象
    新生成的大對象(-XX:+PretenuerSizeThreshold)
  • 5.觸發(fā)Full GC的條件
    老年代空間不足
    永久代空間不足
    CMS GC時出現(xiàn)promotion fail丹拯,concurrent mode failure
    Minor GC晉升到老年代的平均大小大于老年代的剩余空間
    調(diào)用System.gc()
    使用RMI來進(jìn)行RPC或管理的JDK應(yīng)用站超,每小時執(zhí)行一次Full GC

16.springboot注解自動配置原理

@SpringBootApplication 這個注解是個組合注解,其中包含了@EnableAutoConfiguration自動注解類,這個類使用@Import方法注入AutoConfigurationImportSelector.class對象


image.png

image.png

這個類有個方法叫做selectImports,他通過SpringFactoriesLoader.loadFactoryNames先拿到這個自動注解的包名,之后按照這個包名保存到一個map中,


image.png

image.png

讀取配置文件META-INF/spring.factories 其中配置了默認(rèn)加載的類的列表

17.目前mysql有哪幾種索引

1.普通索引
是最基本的索引荸恕,它沒有任何限制乖酬。它有以下幾種創(chuàng)建方式:
(1)直接創(chuàng)建索引
CREATE INDEX index_name ON table(column(length))
(2)修改表結(jié)構(gòu)的方式添加索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length))
(3)創(chuàng)建表的時候同時創(chuàng)建索引
CREATE TABLE table ( id int(11) NOT NULL AUTO_INCREMENT , title char(255) CHARACTER NOT NULL , content text CHARACTER NULL , time int(10) NULL DEFAULT NULL , PRIMARY KEY (id), INDEX index_name (title(length)) )
2.唯一索引
與前面的普通索引類似,不同的就是:索引列的值必須唯一融求,但允許有空值咬像。如果是組合索引,則列值的組合必須唯一生宛。它有以下幾種創(chuàng)建方式:
(1)創(chuàng)建唯一索引
CREATE UNIQUE INDEX indexName ON table(column(length))
(2)修改表結(jié)構(gòu)
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))
(3)創(chuàng)建表的時候直接指定
CREATE TABLE table ( id int(11) NOT NULL AUTO_INCREMENT , title char(255) CHARACTER NOT NULL , content text CHARACTER NULL , time int(10) NULL DEFAULT NULL , UNIQUE indexName (title(length)) );
(4)刪除索引
DROP INDEX index_name ON table
3.主鍵索引
是一種特殊的唯一索引县昂,一個表只能有一個主鍵,不允許有空值陷舅。一般是在建表的時候同時創(chuàng)建主鍵索引:
CREATE TABLE table ( id int(11) NOT NULL AUTO_INCREMENT , title char(255) NOT NULL , PRIMARY KEY (id) );
4.組合索引
指多個字段上創(chuàng)建的索引倒彰,只有在查詢條件中使用了創(chuàng)建索引時的第一個字段,索引才會被使用莱睁。使用組合索引時遵循最左前綴集合
ALTER TABLE table ADD INDEX name_city_age (name,city,age);
5.全文索引
主要用來查找文本中的關(guān)鍵字待讳,而不是直接與索引中的值相比較。fulltext索引跟其它索引大不相同仰剿,它更像是一個搜索引擎创淡,而不是簡單的where語句的參數(shù)匹配。fulltext索引配合match against操作使用南吮,而不是一般的where語句加like琳彩。它可以在create table,alter table 部凑,create index使用露乏,不過目前只有char、varchar涂邀,text 列上可以創(chuàng)建全文索引瘟仿。值得一提的是,在數(shù)據(jù)量較大時候必孤,現(xiàn)將數(shù)據(jù)放入一個沒有全局索引的表中猾骡,然后再用CREATE index創(chuàng)建fulltext索引瑞躺,要比先為一張表建立fulltext然后再將數(shù)據(jù)寫入的速度快很多。
(1)創(chuàng)建表的適合添加全文索引
CREATE TABLE table ( id int(11) NOT NULL AUTO_INCREMENT , title char(255) CHARACTER NOT NULL , content text CHARACTER NULL , time int(10) NULL DEFAULT NULL , PRIMARY KEY (id), FULLTEXT (content) );
(2)修改表結(jié)構(gòu)添加全文索引
ALTER TABLE article ADD FULLTEXT index_content(content)
(3)直接創(chuàng)建索引
CREATE FULLTEXT INDEX index_content ON article(content)

18.mysql的MyISAM和innodb 區(qū)別

MySQL默認(rèn)采用的是MyISAM兴想。
MyISAM不支持事務(wù)幢哨,而InnoDB支持。InnoDB的AUTOCOMMIT默認(rèn)是打開的嫂便,即每條SQL語句會默認(rèn)被封裝成一個事務(wù)捞镰,自動提交,這樣會影響速度毙替,所以最好是把多條SQL語句顯示放在begin和commit之間岸售,組成一個事務(wù)去提交。
InnoDB支持?jǐn)?shù)據(jù)行鎖定厂画,MyISAM不支持行鎖定凸丸,只支持鎖定整個表。即 MyISAM同一個表上的讀鎖和寫鎖是互斥的袱院,MyISAM并發(fā)讀寫時如果等待隊列中既有讀請求又有寫請求屎慢,默認(rèn)寫請求的優(yōu)先級高,即使讀請求先到忽洛,所以 MyISAM不適合于有大量查詢和修改并存的情況腻惠,那樣查詢進(jìn)程會長時間阻塞。因為MyISAM是鎖表欲虚,所以某項讀操作比較耗時會使其他寫進(jìn)程餓死集灌。
InnoDB支持外鍵,MyISAM不支持复哆。
InnoDB的主鍵范圍更大欣喧,最大是MyISAM的2倍。
InnoDB不支持全文索引寂恬,而MyISAM支持续誉。全文索引是指對char辖试、 varchar和text中的每個詞(停用詞除外)建立倒排序索引涕蜂。MyISAM的全文索引其實沒啥用,因為它不支持中文分詞滥比,必須由使用者分詞后加入空 格再寫到數(shù)據(jù)表里牙咏,而且少于4個漢字的詞會和停用詞一樣被忽略掉臼隔。
MyISAM支持GIS數(shù)據(jù),InnoDB不支持妄壶。即MyISAM支持以下空間數(shù)據(jù)對象:Point,Line,Polygon,Surface等摔握。
沒有where的count()使用MyISAM要比InnoDB快得多。因 為MyISAM內(nèi)置了一個計數(shù)器丁寄,count()時它直接從計數(shù)器中讀氨淌,而InnoDB必須掃描全表泊愧。所以在InnoDB上執(zhí)行count()時一般 要伴隨where,且where中要包含主鍵以外的索引列盛正。為什么這里特別強(qiáng)調(diào)“主鍵以外”删咱?因為InnoDB中primary index是和raw data存放在一起的,而secondary index則是單獨存放豪筝,然后有個指針指向primary key痰滋。所以只是count()的話使用secondary index掃描更快,而primary key則主要在掃描索引同時要返回raw data時的作用較大续崖。

19.rocketmq架構(gòu)原理

image.png
  • Broker
    broker主要用于producer和consumer接收和發(fā)送消息
    broker會定時向nameserver提交自己的信息
    是消息中間件的消息存儲敲街、轉(zhuǎn)發(fā)服務(wù)器
    每個Broker節(jié)點,在啟動時严望,都會遍歷NameServer列表多艇,與每個NameServer建立長連接,注冊自己的信息著蟹,之后定時上報
  • Nameserver
    理解成zookeeper的效果墩蔓,只是他沒用zk梢莽,而是自己寫了個nameserver來替代zk
    底層由netty實現(xiàn)萧豆,提供了路由管理、服務(wù)注冊昏名、服務(wù)發(fā)現(xiàn)的功能涮雷,是一個無狀態(tài)節(jié)點
    nameserver是服務(wù)發(fā)現(xiàn)者,集群中各個角色(producer轻局、broker洪鸭、consumer等)都需要定時向nameserver上報自己的狀態(tài),以便互相發(fā)現(xiàn)彼此仑扑,超時不上報的話览爵,nameserver會把它從列表中剔除nameserver可以部署多個,當(dāng)多個nameserver存在的時候镇饮,其他角色同時向他們上報信息蜓竹,以保證高可用,NameServer集群間互不通信储藐,沒有主備的概念nameserver內(nèi)存式存儲俱济,nameserver中的broker、topic等信息默認(rèn)不會持久化钙勃,所以他是無狀態(tài)節(jié)點
  • Producer
    消息的生產(chǎn)者隨機(jī)選擇其中一個NameServer節(jié)點建立長連接蛛碌,獲得Topic路由信息(包括topic下的queue,這些queue分布在哪些broker上等等)接下來向提供topic服務(wù)的master建立長連接(因為rocketmq只有master才能寫消息)辖源,且定時向master發(fā)送心跳
  • Consumer
    消息的消費(fèi)者通過NameServer集群獲得Topic的路由信息蔚携,連接到對應(yīng)的Broker上消費(fèi)消息由于Master和Slave都可以讀取消息希太,因此Consumer會與Master和Slave都建立連接進(jìn)行消費(fèi)消息
  • 核心流程
    Broker都注冊到Nameserver上
    Producer發(fā)消息的時候會從Nameserver上獲取發(fā)消息的topic信息
    Producer向提供服務(wù)的所有master建立長連接,且定時向master發(fā)送心跳
    Consumer通過NameServer集群獲得Topic的路由信息
    Consumer會與所有的Master和所有的Slave都建立連接進(jìn)行監(jiān)聽新消息

20.堆積的消息會不會進(jìn)死信隊列酝蜒?

不會跛十,消息在消費(fèi)失敗后會進(jìn)入重試隊列(%RETRY%+ConsumerGroup),18次(默認(rèn)18次秕硝,網(wǎng)上所有文章都說是16次芥映,無一例外。但是我沒搞懂為啥是16次远豺,這不是18個時間嗎 奈偏?)才會進(jìn)入死信隊列(%DLQ%+ConsumerGroup)。

21.堆積時間過長消息超時了躯护?

RocketMQ中的消息只會在commitLog被刪除的時候才會消失惊来,不會超時。也就是說未被消費(fèi)的消息不會存在超時刪除這情況棺滞。

22.分代收集算法

分代收集法是目前大部分 JVM 所采用的方法裁蚁,其核心思想是根據(jù)對象存活的不同生命周期將內(nèi)存
劃分為不同的域,一般情況下將 GC 堆劃分為老生代(Tenured/Old Generation)和新生代(Young
Generation)继准。老生代的特點是每次垃圾回收時只有少量對象需要被回收枉证,新生代的特點是每次垃
圾回收時都有大量垃圾需要被回收,因此可以根據(jù)不同區(qū)域選擇不同的算法移必。

23.Rocketmq每個Broker與Name Server集群中的所有節(jié)點建立長連接

1室谚、這樣可以使Name Server之間可以沒有任何關(guān)聯(lián),因為它們綁定的Broker是一致的崔泵。
2秒赤、作為Producer或者Consumer可以綁定任何一個Name Server 因為它們都是一樣的.
3.容錯率比較高,就算某一臺nameServer掛掉也不會影響其他服務(wù)

24.app微信登錄圖解

image.png

登錄流程: 手機(jī)端單擊微信,拉起微信授權(quán),單擊同意,微信會返回最終code值,微信返回第三方app,之后拿著code請求我們后端接口,根據(jù)code接口請求最終的用戶信息包括openid,查詢數(shù)據(jù)庫是否是存在該用戶,存在直接返回token信息.

25.pc微信登錄

image.png

登錄流程:pc單擊登陸按鈕跳轉(zhuǎn)微信二維碼,跳轉(zhuǎn)二維碼的時候需要攜帶appid信息,掃描二維碼會請求微信后端,并回調(diào)第三方服務(wù),第三方服務(wù)設(shè)置重定向并攜帶登錄信息,前端拿到登錄信息后進(jìn)行登錄.這個和app登錄不相同的地方是, app登錄的時候 code是app主動調(diào)用后端接口,而pc則是 微信回調(diào)傳輸?shù)腸ode值

25. 使用futureTask創(chuàng)建線程

import java.util.concurrent.Callable;
public class Task implements Callable<Integer>{
    
    @Override
    public Integer call() throws Exception {
        System.out.println("子線程在進(jìn)行計算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}
package com.demo.test
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class CallableTest1 {
    public static void main(String[] args) {
        //第一種方式
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        executor.submit(futureTask);
        executor.shutdown();
        //第二種方式,注意這種方式和第一種方式效果是類似的憎瘸,只不過一個使用的是ExecutorService入篮,一個使用的是Thread
//        Task task = new Task();
//        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
//        Thread thread = new Thread(futureTask);
//        thread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println("主線程在執(zhí)行任務(wù)");
        try {
            if(futureTask.get()!=null){  
                System.out.println("task運(yùn)行結(jié)果"+futureTask.get());
            }else{
                System.out.println("future.get()未獲取到結(jié)果"); 
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("所有任務(wù)執(zhí)行完畢"); }}

26.springboot加載bean的幾種方式

  • 1.如果是復(fù)雜的依賴進(jìn)去的jar環(huán)境可以使用spring.factories在中進(jìn)行配置bean resources/META-INF/spring.factories 其中
    org.springframework.boot.autoconfigure.EnableAutoConfiguration top.huic.logrecord.plus.ui.LogRecordPlusUiStart
    代表自動配置的 key,即代表需要自動配置哪些類幌甘,\ 可以理解為一個換行符潮售,則該行下面的每行當(dāng)做一個參數(shù)
  • 2.@Configuration是聲明為一個配置類@ComponentScan是設(shè)置自動掃描包,讓Spring能夠發(fā)現(xiàn)我們封裝的組件的其他 Spring Bean,@Import直接寫入包名也可直接注入

27. springcache緩存,本地的二級緩存 redis發(fā)布訂閱模式整合

使用 RedisMessageListenerContainer 調(diào)用 addMessageListener添加監(jiān)聽topic,使用redistemplate提供的convertAndSend發(fā)送消息,這個發(fā)布訂閱是廣播模式,每個收到這個生產(chǎn)者消息的時候都會進(jìn)行消費(fèi),清除本地緩存,自定義cache繼AbstractValueAdaptingCache抽象類重寫put方法,evict方法,clear,lookup查詢方法添加上本地緩存同時在對應(yīng)方法寫上redistemplate的生產(chǎn)消息方法,創(chuàng)建cachemanager并實現(xiàn)cachemanager方法,覆蓋getCache方法,改成自定義cache類,

28.zookeeper分布式鎖原理

首先含潘,Zookeeper的每一個節(jié)點饲做,都是一個天然的順序發(fā)號器。
在每一個節(jié)點下面創(chuàng)建子節(jié)點時遏弱,只要選擇的創(chuàng)建類型是有序(EPHEMERAL_SEQUENTIAL 臨時有序或者PERSISTENT_SEQUENTIAL 永久有序)類型盆均,那么,新的子節(jié)點后面漱逸,會加上一個次序編號泪姨。這個次序編號游沿,是上一個生成的次序編號加一比如,創(chuàng)建一個用于發(fā)號的節(jié)點“/test/lock”肮砾,然后以他為父親節(jié)點诀黍,可以在這個父節(jié)點下面創(chuàng)建相同前綴的子節(jié)點,假定相同的前綴為“/test/lock/seq-”仗处,在創(chuàng)建子節(jié)點時眯勾,同時指明是有序類型。如果是第一個創(chuàng)建的子節(jié)點婆誓,那么生成的子節(jié)點為/test/lock/seq-0000000000吃环,下一個節(jié)點則為/test/lock/seq-0000000001,依次類推洋幻,等等郁轻。


image.png

其次,Zookeeper節(jié)點的遞增性文留,可以規(guī)定節(jié)點編號最小的那個獲得鎖好唯。
一個zookeeper分布式鎖,首先需要創(chuàng)建一個父節(jié)點燥翅,盡量是持久節(jié)點(PERSISTENT類型)骑篙,然后每個要獲得鎖的線程都會在這個節(jié)點下創(chuàng)建個臨時順序節(jié)點,由于序號的遞增性权旷,可以規(guī)定排號最小的那個獲得鎖替蛉。所以,每個線程在嘗試占用鎖之前拄氯,首先判斷自己是排號是不是當(dāng)前最小,如果是它浅,則獲取鎖译柏。

29.Mysql使用索引為什么會變快?

檢索中主要耗時在于內(nèi)存與磁盤的IO耗時姐霍,所以加速的關(guān)鍵在于減少IO的次數(shù)鄙麦。


image.png

圖中是一顆 b 樹,每個磁盤塊包含幾個數(shù)據(jù)項和指針镊折,
如磁盤塊 1 包含數(shù)據(jù)項 17 和 35胯府,包含指針 P1、P2恨胚、P3骂因,
P1指向包含數(shù)據(jù)項小于17的磁盤塊,P2指向數(shù)據(jù)項在17和35之間的磁盤塊赃泡,P3 指向數(shù)據(jù)項大于35的磁盤塊寒波。真實的數(shù)據(jù)存在于葉子節(jié)點乘盼,即 3、5俄烁、9绸栅、10、13页屠、15粹胯、28、29辰企、36矛双、60、75蟆豫、79议忽、90、99十减。非葉子節(jié)點只不存儲真實的數(shù)據(jù)栈幸,只存儲指引搜索方向的數(shù)據(jù)項,如 17帮辟、35 并不真實存在于數(shù)據(jù)表中速址。
【查找過程】 以查找數(shù)據(jù)項29為例
首先會把磁盤塊 1 由磁盤加載到內(nèi)存,此時發(fā)生一次 IO由驹,在內(nèi)存中用二分查找確定29在17和35之間芍锚,鎖定磁盤塊1的 P2指針,相比磁盤的 IO蔓榄,內(nèi)存時間非常短可以忽略不計并炮。通過磁盤塊 1的 P2 指針的磁盤地址把磁盤塊 3 由磁盤加載到內(nèi)存,發(fā)生第二次 IO甥郑,29 在 26 和 30 之間逃魄,同理鎖定磁盤塊 3 的 P2 指針。通過指針加載磁盤塊 8 到內(nèi)存澜搅,發(fā)生第三次 IO伍俘,同時內(nèi)存中做二分查找找到了數(shù)據(jù)項 29,結(jié)束查詢勉躺,總計三次 IO癌瘾。

30.mybatis是如何從xml文件查詢到對應(yīng)的文件的

31.redis分布式鎖機(jī)制,如果該鎖過期之后怎么辦

Redisson是一個在Redis的基礎(chǔ)上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象饵溅,還提供了許多分布式服務(wù)妨退。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進(jìn)使用者對Redis的關(guān)注分離(Separation of Concern),從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務(wù)邏輯上碧注。

// 最常見的使用方法
lock.lock();
lock.unlock()

// 加鎖以后10秒鐘自動解鎖
// 無需調(diào)用unlock方法手動解鎖
lock.lock(10, TimeUnit.SECONDS);

// 嘗試加鎖嚣伐,最多等待100秒,上鎖以后10秒自動解鎖
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
lock.unlock();

//公平鎖
RLock fairLock = redisson.getFairLock("anyLock");
// 最常見的使用方法
fairLock.lock();

32.mysql的行級鎖和表級鎖

mysql行級鎖注意幾點:
1萍丐、行鎖必須有索引才能實現(xiàn)轩端,否則會自動鎖全表,那么就不是行鎖了逝变。
2基茵、兩個事務(wù)不能鎖同一個索引(不能有鎖住有交集的行).
例如:
事務(wù)A先執(zhí)行:select math from zje where math>60 for update;
事務(wù)B再執(zhí)行:select math from zje where math<60 for update;
行級鎖又分共享鎖和排他鎖壳影。
名詞解釋:

  • 1.共享鎖
    共享鎖又叫做讀鎖拱层,所有的事務(wù)只能對其進(jìn)行讀操作不能寫操作,加上共享鎖后在事務(wù)結(jié)束之前其他事務(wù)只能再加共享鎖宴咧,除此之外其他任何類型的鎖都不能再加了根灯。
    用法:SELECT id FROM table WHERE id in(1,2) LOCK IN SHARE MODE 結(jié)果集的數(shù)據(jù)都會加共享鎖
  • 2.排他鎖
    名詞解釋:若某個事物對某一行加上了排他鎖,只能這個事務(wù)對其進(jìn)行讀寫掺栅,在此事務(wù)結(jié)束之前烙肺,其他事務(wù)不能對其進(jìn)行加任何鎖,其他進(jìn)程可以讀取,不能進(jìn)行寫操作氧卧,需等待其釋放桃笙。
    用法:SELECT id FROM mk_user WHERE id=1 FOR UPDATE
    鎖沖突:例如說事務(wù)A將某幾行上鎖后,事務(wù)B又對其上鎖沙绝,鎖不能共存否則會出現(xiàn)鎖沖突搏明。(但是共享鎖可以共存,共享鎖和排它鎖不能共存闪檬,排它鎖和排它鎖也不可以)星著。
    死鎖:例如說兩個事務(wù),事務(wù)A鎖住了1-5行谬以,同時事務(wù)B鎖住了6-10行强饮,此時事務(wù)A請求鎖住6-10行,就會阻塞直到事務(wù)B施放6-10行的鎖为黎,而隨后事務(wù)B又請求鎖住1-5行,事務(wù)B也阻塞直到事務(wù)A釋放1~5行的鎖行您。死鎖發(fā)生時铭乾,會產(chǎn)生Deadlock錯誤。
    3娃循、insert 炕檩,delete , update在事務(wù)中都會自動默認(rèn)加上排它鎖(寫)。
    會話1:select math from zje where math>60 for update笛质;
    會話2:update zje set math=99 where math=68泉沾;阻塞...........
    如上,會話1先把zje表中math>60的行上排它鎖妇押。然后會話2試圖把math=68的行進(jìn)行修改跷究,math=68處于math>60中,所以是已經(jīng)被鎖的敲霍,會話2進(jìn)行操作時俊马,就會阻塞,等待會話1把鎖釋放肩杈。當(dāng)commit時或者程序結(jié)束時柴我,會釋放鎖。

33.springboot如何更換tomcat

只需要修改tomcat即可實現(xiàn)替換tomcat

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

34.java本地事務(wù)失效的原因

1.當(dāng)前類沒有交給spring進(jìn)行管理
2.目標(biāo)方式不是public,事務(wù)默認(rèn)直接進(jìn)行忽略


image.png

3.自己調(diào)用自己的方法的時候事務(wù)也是會失效的,其本質(zhì)上是因為最終生成的代理類,最終調(diào)用還是原始的方法,

 
    private DmzService dmzService;
 
    public DmzServiceProxy(DmzService dmzService) {
        this.dmzService = dmzService;
    }
 
    public void saveAB(A a, B b) {
        dmzService.saveAB(a, b);
    }
 
    public void saveA(A a) {
        try {
            // 開啟事務(wù)
            startTransaction();
            dmzService.saveA(a);
        } catch (Exception e) {
            // 出現(xiàn)異忱┤唬回滾事務(wù)
            rollbackTransaction();
        }
        // 提交事務(wù)
        commitTransaction();
    }
 
    public void saveB(B b) {
        try {
            // 開啟事務(wù)
            startTransaction();
            dmzService.saveB(b);
        } catch (Exception e) {
            // 出現(xiàn)異乘胰澹回滾事務(wù)
            rollbackTransaction();
        }
        // 提交事務(wù)
        commitTransaction();
    }
}

35.mysql索引回表問題

mysql說起回表問題,要從從mysql的聚集索引和非聚集索引說起,聚集索引指的是以主鍵建立的索引中他是帶有當(dāng)前表的所有數(shù)據(jù)的,當(dāng)然如果當(dāng)前沒有定義主鍵的話,他是按照當(dāng)前表中具有唯一性的字段作為索引,去簡歷聚集索引,當(dāng)前聚集索引的葉子結(jié)點存儲的是當(dāng)前的行記錄, 而非聚集索引指的其他非主鍵去建立的索引 這種1索引是沒有存儲行記錄的,
比如在name字段加上索引,然后按照name進(jìn)行查詢 select * 他會查詢兩邊索引,先查詢name索引樹,name索引樹上掛載的當(dāng)前行記錄的id,他拿到id需要去id索引樹下進(jìn)行查詢,id索引樹下掛載的是完整的行記錄

36.mysql 索引最左原則原理

B+數(shù)

索引本質(zhì)是一棵B+Tree,聯(lián)合索引(col1, col2,col3)也是夫偶。其非葉子節(jié)點存儲的是第一個關(guān)鍵字的索引界睁,而葉節(jié)點存儲的則是三個關(guān)鍵字col1、col2索守、col3三個關(guān)鍵字的數(shù)據(jù)晕窑,且按照col1、col2卵佛、col3的順序進(jìn)行排序杨赤。聯(lián)合索引(年齡, 姓氏,名字),葉節(jié)點上data域存儲的是三個關(guān)鍵字的數(shù)據(jù)截汪。且是按照年齡疾牲、姓氏、名字的順序排列的衙解。而最左原則的原理就是阳柔,因為聯(lián)合索引的B+Tree是按照第一個關(guān)鍵字進(jìn)行索引排列的。

37.B+樹和B樹有什么區(qū)別

只有葉子節(jié)點存儲data蚓峦,葉子節(jié)點包含了這棵樹的所有鍵值蝴罪,葉子節(jié)點不存儲指針。每個節(jié)點都存儲key和data催训,所有節(jié)點組成這棵樹现使,并且葉子節(jié)點指針為null。
B+樹的葉子節(jié)點會用指針將數(shù)據(jù)串聯(lián)起來,B樹葉子結(jié)點是空的只有鍵值存儲數(shù)據(jù),B+樹是葉子結(jié)點存儲數(shù)據(jù)

38.hashMap 擴(kuò)充過程會有什么安全隱患?

hashmpa默認(rèn)長度是16,超過16的時候就需要進(jìn)行擴(kuò)充,當(dāng)再擴(kuò)充的時候,如果多個線程去操作他的話,就會出現(xiàn)循環(huán)鏈表,hashMpa擴(kuò)充的機(jī)制,

39.count(*) 和 count(1)區(qū)別

count(字段)一汽,根絕字段判斷為不為不空避消,根據(jù)字段定義,考慮要不要累加返回值,既然你引擎都返回值了岩喷,那我server層 “ +1 ”count(id),根據(jù)id主鍵取值恕沫,累加返回值,也是server層 “ +1 ”count(1)纱意,同樣會遍歷婶溯,但不取值,引擎告訴不為空那我就 “+1”count(),也不取值妇穴,而且人家還是經(jīng)過優(yōu)化的根據(jù)上面的推倒爬虱,搜主鍵肯定比搜正常字段快, 不取值的一定比取值的快(我就是查數(shù)統(tǒng)計一下腾它,你給我這一行所有的值也沒啥用芭荏荨), 優(yōu)化過的比沒優(yōu)化過的快以下排行是按照效率瞒滴,而不是時間count() > count(1) > count(id) > count(字段)

40.linux命令總結(jié)

查找文件內(nèi)容
grep "search content" filename1

41.mybatis是如何將xml轉(zhuǎn)換為sql的

42.sql執(zhí)行順序

from
join
on
where
group by(開始使用select中的別名曲梗,后面的語句中都可以使用)
avg,sum....
having
select
distinct
order by
limit
第一步:首先對from子句中的前兩個表執(zhí)行一個笛卡爾乘積,此時生成虛擬表 vt1(選擇相對小的表做基礎(chǔ)表)妓忍。
第二步:接下來便是應(yīng)用on篩選器虏两,on 中的邏輯表達(dá)式將應(yīng)用到 vt1 中的各個行,篩選出滿足on邏輯表達(dá)式的行世剖,生成虛擬表 vt2 定罢。
第三步:如果是outer join 那么這一步就將添加外部行,left outer jion 就把左表在第二步中過濾的添加進(jìn)來旁瘫,如果是right outer join 那么就將右表在第二步中過濾掉的行添加進(jìn)來祖凫,這樣生成虛擬表 vt3 。
第四步:如果 from 子句中的表數(shù)目多余兩個表酬凳,那么就將vt3和第三個表連接從而計算笛卡爾乘積惠况,生成虛擬表,該過程就是一個重復(fù)1-3的步驟宁仔,最終得到一個新的虛擬表 vt3稠屠。
第五步:應(yīng)用where篩選器,對上一步生產(chǎn)的虛擬表引用where篩選器翎苫,生成虛擬表vt4权埠,在這有個比較重要的細(xì)節(jié)不得不說一下,對于包含outer join子句的查詢煎谍,就有一個讓人感到困惑的問題弊知,到底在on篩選器還是用where篩選器指定邏輯表達(dá)式呢?on和where的最大區(qū)別在于粱快,如果在on應(yīng)用邏輯表達(dá)式那么在第三步outer join中還可以把移除的行再次添加回來,而where的移除的最終的。舉個簡單的例子,有一個學(xué)生表(班級,姓名)和一個成績表(姓名,成績),我現(xiàn)在需要返回一個x班級的全體同學(xué)的成績,但是這個班級有幾個學(xué)生缺考,也就是說在成績表中沒有記錄。為了得到我們預(yù)期的結(jié)果我們就需要在on子句指定學(xué)生和成績表的關(guān)系(學(xué)生.姓名=成績.姓名)那么我們是否發(fā)現(xiàn)在執(zhí)行第二步的時候尊残,對于沒有參加考試的學(xué)生記錄就不會出現(xiàn)在vt2中夜郁,因為他們被on的邏輯表達(dá)式過濾掉了,但是我們用left outer join就可以把左表(學(xué)生)中沒有參加考試的學(xué)生找回來屎即,因為我們想返回的是x班級的所有學(xué)生统台,如果在on中應(yīng)用學(xué)生.班級='x'的話谤逼,left outer join會把x班級的所有學(xué)生記錄找回(感謝網(wǎng)友康欽謀__康欽苗的指正)枝冀,所以只能在where篩選器中應(yīng)用學(xué)生.班級='x' 因為它的過濾是最終的谷誓。
第六步:group by 子句將中的唯一的值組合成為一組绒障,得到虛擬表vt5端盆。如果應(yīng)用了group by费封,那么后面的所有步驟都只能得到的vt5的列或者是聚合函數(shù)(count焕妙、sum、avg等)末患。原因在于最終的結(jié)果集中只為每個組包含一行渊啰。這一點請牢記绘证。
第七步:應(yīng)用cube或者rollup選項隧膏,為vt5生成超組,生成vt6.
第八步:應(yīng)用having篩選器嚷那,生成vt7胞枕。having篩選器是第一個也是為唯一一個應(yīng)用到已分組數(shù)據(jù)的篩選器。
第九步:處理select子句魏宽。將vt7中的在select中出現(xiàn)的列篩選出來腐泻。生成vt8.
第十步:應(yīng)用distinct子句决乎,vt8中移除相同的行,生成vt9贫悄。事實上如果應(yīng)用了group by子句那么distinct是多余的瑞驱,原因同樣在于,分組的時候是將列中唯一的值分成一組窄坦,同時只為每一組返回一行記錄,那么所以的記錄都將是不相同的凳寺。
第十一步:應(yīng)用order by子句鸭津。按照order_by_condition排序vt9,此時返回的一個游標(biāo)肠缨,而不是虛擬表逆趋。sql是基于集合的理論的,集合不會預(yù)先對他的行排序晒奕,它只是成員的邏輯集合闻书,成員的順序是無關(guān)緊要的。對表進(jìn)行排序的查詢可以返回一個對象脑慧,這個對象包含特定的物理順序的邏輯組織魄眉。這個對象就叫游標(biāo)。正因為返回值是游標(biāo)闷袒,那么使用order by 子句查詢不能應(yīng)用于表表達(dá)式坑律。排序是很需要成本的,除非你必須要排序囊骤,否則最好不要指定order by晃择,最后,在這一步中是第一個也是唯一一個可以使用select列表中別名的步驟也物。
第十二步:應(yīng)用top選項宫屠。此時才返回結(jié)果給請求者即用戶。

from tb_Grade 
where 考生姓名 is not null 
group by 考生姓名 
having max(總成績) > 600 
order by max總成績 

(1)首先執(zhí)行 FROM 子句, 從 tb_Grade 表組裝數(shù)據(jù)源的數(shù)據(jù)
(2). 執(zhí)行 WHERE 子句, 篩選 tb_Grade 表中所有數(shù)據(jù)不為 NULL 的數(shù)據(jù)
(3). 執(zhí)行 GROUP BY 子句, 把 tb_Grade 表按 "學(xué)生姓名" 列進(jìn)行分組(注:這一步開始才可以使用select中的別名滑蚯,他返回的是一個游標(biāo)浪蹂,而不是一個表,所以在where中不可以使用select中的別名膘魄,而having卻可以使用乌逐,感謝網(wǎng)友 zyt1369 提出這個問題)
(4). 計算 max() 聚集函數(shù), 按 "總成績" 求出總成績中最大的一些數(shù)值
(5). 執(zhí)行 HAVING 子句, 篩選課程的總成績大于 600 分的.
(7). 執(zhí)行 ORDER BY 子句, 把最后的結(jié)果按 "Max 成績" 進(jìn)行排序.

43.紅黑樹結(jié)構(gòu)

image.png

1.每個節(jié)點只能是紅色或者黑色。
2.根節(jié)點必須是黑色创葡。
3.紅色的節(jié)點浙踢,它的葉節(jié)點只能是黑色。
4.從任一節(jié)點到其每個葉子的所有路徑都包含相同數(shù)目的黑色節(jié)點灿渴。

44.redis內(nèi)存滿的時候的緩存淘汰算法

FIFO

  1. FIFO(First in First out)洛波,先進(jìn)先出胰舆。在FIFO Cache設(shè)計中,核心原則就是:如果一個數(shù)據(jù)最先進(jìn)入緩存中蹬挤,則應(yīng)該最早淘汰掉缚窿。
    1、利用一個雙向鏈表保存數(shù)據(jù)焰扳,
    2倦零、當(dāng)來了新的數(shù)據(jù)之后便添加到鏈表末尾,
    3吨悍、如果Cache存滿數(shù)據(jù)扫茅,則把鏈表頭部數(shù)據(jù)刪除,
    4育瓜、然后把新的數(shù)據(jù)添加到鏈表末尾葫隙。
    5、在訪問數(shù)據(jù)的時候躏仇,如果在Cache中存在該數(shù)據(jù)的話恋脚,則返回對應(yīng)的value值;
    6焰手、否則返回-1糟描。如果想提高訪問效率,可以利用hashmap來保存每個key在鏈表中對應(yīng)的位置册倒。
    FIFO是最簡單的淘汰策略蚓挤,遵循著先進(jìn)先出的原則,這里簡單提一下:


    image.png
  2. LRU(Least Recently Used)表示最近最少使用驻子,該算法根據(jù)數(shù)據(jù)的歷史訪問記錄來進(jìn)行淘汰數(shù)據(jù)灿意,其核心思想是“如果數(shù)據(jù)最近被訪問過,那么將來被訪問的幾率也更高”崇呵。LRU算法的常見實現(xiàn)方式為鏈表:新數(shù)據(jù)放在鏈表頭部 缤剧,鏈表中的數(shù)據(jù)被訪問就移動到鏈頭,鏈表滿的時候從鏈表尾部移出數(shù)據(jù)域慷。


    image.png

    3.LFU算法
    LFU(Least Frequently Used)表示最不經(jīng)常使用荒辕,它是根據(jù)數(shù)據(jù)的歷史訪問頻率來淘汰數(shù)據(jù),其核心思想是“如果數(shù)據(jù)過去被訪問多次犹褒,那么將來被訪問的頻率也高”抵窒。
    LFU算法反映了一個key的熱度情況,不會因LRU算法的偶爾一次被訪問被誤認(rèn)為是熱點數(shù)據(jù)叠骑。LFU算法的常見實現(xiàn)方式為鏈表:新數(shù)據(jù)放在鏈表尾部 李皇,鏈表中的數(shù)據(jù)按照被訪問次數(shù)降序排列,訪問次數(shù)相同的按最近訪問時間降序排列宙枷,鏈表滿的時候從鏈表尾部移出數(shù)據(jù)掉房。


    image.png

45.redis的過期刪除key的策略

在Redis中過期的key不會立刻從內(nèi)存中刪除茧跋,而是會同時以下面兩種策略進(jìn)行刪除:惰性刪除:當(dāng)key被訪問時檢查該key的過期時間,若已過期則刪除卓囚;已過期未被訪問的數(shù)據(jù)仍保持在內(nèi)存中瘾杭,消耗內(nèi)存資源;
定期刪除:每隔一段時間哪亿,隨機(jī)檢查設(shè)置了過期的key并刪除已過期的key粥烁;維護(hù)定時器消耗CPU資源;
Redis每10秒進(jìn)行一次過期掃描:
隨機(jī)取20個設(shè)置了過期策略的key锣夹;
檢查20個key中過期時間中已過期的key并刪除页徐;
如果有超過25%的key已過期則重復(fù)第一步;

46.AOF和RDB的過期刪除策略

1.RDB對過期建的處理
在啟動 Redis 服務(wù)器時银萍,如果服務(wù)器開啟了 RDB 功能,那么服務(wù)器將對 RDB 文件進(jìn)行載入:
如果服務(wù)器以主服務(wù)器模式運(yùn)行恤左,那么在載入 RDB 文件時贴唇,程序會對文件中保存的鍵進(jìn)行檢查,未過期的鍵會被載入到數(shù)據(jù)庫中飞袋,而過期鍵則會被忽略戳气,所以過期鍵對載入RDB 文件的主服務(wù)器不會造成影響。
如果服務(wù)器以從服務(wù)器模式運(yùn)行巧鸭,那么在載入 RDB 文件時瓶您,文件中保存的所有鍵,不論是否過期纲仍,都會被載入到數(shù)據(jù)庫中呀袱。不過,因為主從服務(wù)器在進(jìn)行數(shù)據(jù)同步的時候郑叠,從服務(wù)器的數(shù)據(jù)庫就會被清空夜赵,所以一般來講,過期鍵對載入 RDB 文件的從服務(wù)器也不會造成影響乡革。
2.AOF 持久化功能對過期鍵的處理
AOF文件的寫入
當(dāng)服務(wù)器以 AOF 持久化模式運(yùn)行時寇僧, 如果數(shù)據(jù)庫中的某個鍵已經(jīng)過期,但它還沒有被惰性刪除或者定期刪除沸版,那么 AOF文件不會因為這個過期鍵而產(chǎn)生任何 影響嘁傀。 當(dāng)過期鍵被惰性刪除或者定期刪除之后,程序會向 AOF 文件追加(append)一條 DEL 命令视粮,來顯式地記錄該鍵已被刪除细办。
AOF文件載入
和生成 RDB 文件時類似,在執(zhí)行 AOF 重寫的過程中馒铃,程序會對數(shù)據(jù)庫中的鍵進(jìn)行檢查蟹腾,已過期的鍵不會被保存到重寫后的 AOF 文件中痕惋。
過期刪除操作統(tǒng)一在 master 實例中進(jìn)行并向下傳遞,而不是各 salve 各自處理娃殖。這樣一來便不會出現(xiàn)數(shù)據(jù)不一致的情形值戳。
擴(kuò)展
當(dāng) slave 連接到 master 后并不能立即清理已過期的 key(需要等待由master傳遞過來的DEL操作),slave 仍需對數(shù)據(jù)集中的過期狀態(tài)進(jìn)行管理維護(hù)以便于在 slave 被選為 master 時能像 master 一樣獨立的進(jìn)行過期處理炉爆。

47.類加載機(jī)制

1.類加載的過程
我們編寫的java文件都是保存著業(yè)務(wù)邏輯代碼堕虹。java編譯器將 .java 文件編譯成擴(kuò)展名為 .class 的文件。.class 文件中保存著java轉(zhuǎn)換后芬首,虛擬機(jī)將要執(zhí)行的指令赴捞。當(dāng)需要某個類的時候,java虛擬機(jī)會加載 .class 文件郁稍,并創(chuàng)建對應(yīng)的class對象赦政,將class文件加載到虛擬機(jī)的內(nèi)存,這個過程被稱為類的加載耀怜。

image.png

加載
類加載過程的一個階段恢着,ClassLoader通過一個類的完全限定名查找此類字節(jié)碼文件,并利用字節(jié)碼文件創(chuàng)建一個class對象财破。
驗證
目的在于確保class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機(jī)要求掰派,不會危害虛擬機(jī)自身的安全,主要包括四種驗證:文件格式的驗證左痢,元數(shù)據(jù)的驗證靡羡,字節(jié)碼驗證,符號引用驗證俊性。
準(zhǔn)備
為類變量(static修飾的字段變量)分配內(nèi)存并且設(shè)置該類變量的初始值略步,(如static int i = 5 這里只是將 i 賦值為0,在初始化的階段再把 i 賦值為5)磅废,這里不包含final修飾的static 纳像,因為final在編譯的時候就已經(jīng)分配了。這里不會為實例變量分配初始化拯勉,類變量會分配在方法區(qū)中竟趾,實例變量會隨著對象分配到Java堆中。
解析
這里主要的任務(wù)是把常量池中的符號引用替換成直接引用
初始化
這里是類記載的最后階段宫峦,如果該類具有父類就進(jìn)行對父類進(jìn)行初始化岔帽,執(zhí)行其靜態(tài)初始化器(靜態(tài)代碼塊)和靜態(tài)初始化成員變量。(前面已經(jīng)對static 初始化了默認(rèn)值导绷,這里我們對它進(jìn)行賦值犀勒,成員變量也將被初始化)
類記載器的任務(wù)是根據(jù)類的全限定名來讀取此類的二進(jìn)制字節(jié)流到 JVM 中,然后轉(zhuǎn)換成一個與目標(biāo)類對象的java.lang.Class 對象的實例,在java 虛擬機(jī)提供三種類加載器贾费,引導(dǎo)類加載器钦购,擴(kuò)展類加載器,系統(tǒng)類加載器褂萧。
forName和loaderClass區(qū)別
Class.forName()得到的class是已經(jīng)初始化完成的押桃。

Classloader.loaderClass得到的class是還沒有鏈接(驗證,準(zhǔn)備导犹,解析三個過程被稱為鏈接的唱凯。

jdk中的加載器
Bootstrp loader
Bootstrp加載器是用C++語言寫的,它是在Java虛擬機(jī)啟動后初始化的谎痢,它主要負(fù)責(zé)加載%JAVA_HOME%/jre/lib,-Xbootclasspath參數(shù)指定的路徑以及%JAVA_HOME%/jre/classes中的類磕昼。
ExtClassLoader
Bootstrp loader加載ExtClassLoader,并且將ExtClassLoader的父加載器設(shè)置Bootstrp loader.ExtClassLoader是用Java寫的,具體來是sun.misc.Launcher ExtClassLoader节猿,ExtClassLoader主要加載/jre/lib/ext票从,此路徑下的所有classes目錄以及java.ext.dirs系統(tǒng)變量指定的路徑中類庫。
AppClassLoader
Bootstrp loader加載完ExtClassLoader后滨嘱,就會加載AppClassLoader,并且將AppClassLoader的父加載器指定為 ExtClassLoader纫骑。AppClassLoader也是用Java寫成的,它的實現(xiàn)類是 sun.misc.Launcher$AppClassLoader九孩,另外我們知道ClassLoader中有個getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要負(fù)責(zé)加載classpath所指定的位置的類或者是jar文檔,它也是Java程序默認(rèn)的類加載器发框。

48. 類加載順序

1)加載過程中會先檢查類是否被已加載躺彬,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查梅惯,只要某個classloader已加載就視為已加載此類宪拥,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下铣减,也就是由上層來逐層嘗試加載此類她君。
2)在加載類時,每個類加載器會將加載任務(wù)上交給其父葫哗,如果其父找不到缔刹,再由自己去加載。
3)Bootstrap Loader(啟動類加載器)是最頂級的類加載器了劣针,其父加載器為null校镐。
垃圾回收器比較
垃圾回收算法性能:
吞吐量:運(yùn)行用戶代碼時間 / (運(yùn)行用戶代碼時間 + 垃圾收集時間)。吞吐量越高捺典,CPU利用越高效鸟廓,則算法越好
最大暫停時間:因 GC 而暫停應(yīng)用程序線程的最長時間技竟。暫停時間越短枣接,則算法越好

49.hashMap初始化容量建議值

image.png

50.hashMap擴(kuò)容機(jī)制

JDK7的擴(kuò)容機(jī)制相對簡單,有以下特性:

  • 空參數(shù)的構(gòu)造函數(shù):以默認(rèn)容量、默認(rèn)負(fù)載因子铅歼、默認(rèn)閾值初始化數(shù)組。內(nèi)部數(shù)組是空數(shù)>組妆兑。
  • 有參構(gòu)造函數(shù):根據(jù)參數(shù)確定容量娃豹、負(fù)載因子、閾值等骏融。
  • 第一次put時會初始化數(shù)組链嘀,其容量變?yōu)?strong>不小于指定容量的2的冪數(shù)。然后根據(jù)負(fù)載因>子確定閾值档玻。
  • 如果不是第一次擴(kuò)容怀泊,則新容量=舊容量2, 新閾值=新容量負(fù)載因子
    JDK8的擴(kuò)容機(jī)制
    JDK8的擴(kuò)容做了許多調(diào)整。
    HashMap的容量變化通常存在以下幾種情況:
  1. 空參數(shù)的構(gòu)造函數(shù):實例化的HashMap默認(rèn)內(nèi)部數(shù)組是null误趴,即沒有實例化霹琼。第一次調(diào)用put方法時,則會開始第一次初始化擴(kuò)容凉当,長度為16枣申。
  2. 有參構(gòu)造函數(shù):用于指定容量。會根據(jù)指定的正整數(shù)找到不小于指定容量的2的冪數(shù)看杭,將這個數(shù)設(shè)置賦值給閾值(threshold)忠藤。第一次調(diào)用put方法時,會將閾值賦值給容量楼雹,然后讓 閾值 = 容量乘于負(fù)載因子
    模孩。(因此并不是我們手動指定了容量就一定不會觸發(fā)擴(kuò)容,超過閾值后一樣會擴(kuò)容V濉Uジ馈)
  3. 如果不是第一次擴(kuò)容,則容量變?yōu)樵瓉淼?倍谴供,閾值也變?yōu)樵瓉淼?倍块茁。(容量和閾值都變?yōu)樵瓉淼?倍時,負(fù)載因子還是不變)
    4.討論當(dāng)前索引擴(kuò)充之后如何重新計算當(dāng)前的hashcode問題
    我們使用的是2次冪的擴(kuò)展(指長度擴(kuò)為原來2倍)桂肌,所以数焊,元素的位置要么是在原位置,要么是在原位置再移動2次冪的位置轴或〔看下圖可以明白這句話的意思,n為table的長度照雁,圖(a)表示擴(kuò)容前的key1和key2兩種key確定索引位置的示例蚕愤,圖(b)表示擴(kuò)容后key1和key2兩種key確定索引位置的示例答恶,其中hash1是key1對應(yīng)的哈希與高位運(yùn)算結(jié)果。
    image.png

    總結(jié)因為在hash中存儲的值的是 拿著hashCode與當(dāng)前hashMap的長度進(jìn)行&運(yùn)算得到的最終結(jié)果,也就是如果當(dāng)計算的hashCode值比當(dāng)前hashMap數(shù)組大小 小的情況下其對應(yīng)的擴(kuò)充之后hashMap索引值是不會變的,我們都知道容量乘于2的時候?qū)嶋H上相當(dāng)于將當(dāng)前容器容量左移1位,但是左移的話,二進(jìn)制就會出現(xiàn)0位,但是他是按照 2 * oldCap - 1,減1操作就會把0全部置換為1,我們知道hashMap初始容量都是2的冪數(shù), 因此對應(yīng)的二進(jìn)制只有開頭有一個1后邊全是0.因此減去1之后就是全部是1了,當(dāng)前old跟hashCode進(jìn)行計算的時候如果hashCode大小沒有old大的話,也就是再參與位運(yùn)算的時候他比old短,那就意味著;不論old擴(kuò)充幾倍,跟hashCode參與運(yùn)算的都是那幾個數(shù)字因此,大小不變,還有一種情況就是如果hashCode比oldCap大的話情況就不同了,這種情況下就要查看hashCode的計算中新增的那一位是0還是1如果是0的話還是不變,如果是1的話就需要變化

51.HashMap中的hash算法

首先要明白一個概念萍诱,HashMap中定位到桶的位置 是根據(jù)Key的hash值與數(shù)組的長度取模來計算的悬嗓。具體的細(xì)節(jié)我就不說了,默認(rèn)認(rèn)為大家都懂這一點裕坊。取陌瘢可以改為:hashCode & (length - 1),這里的數(shù)組長度最好是2的冪數(shù),這樣能減少hashcode碰撞概率

52.cms算法

初始標(biāo)記(STW initial mark)
并發(fā)標(biāo)記(Concurrent marking)
并發(fā)預(yù)清理(Concurrent precleaning)
重新標(biāo)記(STW remark)
并發(fā)清理(Concurrent sweeping)
并發(fā)重置(Concurrent reset)
初始標(biāo)記 :在這個階段,需要虛擬機(jī)停頓正在執(zhí)行的任務(wù)籍凝,官方的叫法STW(Stop The Word)周瞎。這個過程從垃圾回收的”根對象”開始,只掃描到能夠和”根對象”直接關(guān)聯(lián)的對象饵蒂,并作標(biāo)記声诸。所以這個過程雖然暫停了整個JVM,但是很快就完成了退盯。
并發(fā)標(biāo)記 :這個階段緊隨初始標(biāo)記階段彼乌,在初始標(biāo)記的基礎(chǔ)上繼續(xù)向下追溯標(biāo)記。并發(fā)標(biāo)記階段渊迁,應(yīng)用程序的線程和并發(fā)標(biāo)記的線程并發(fā)執(zhí)行慰照,所以用戶不會感受到停頓。
并發(fā)預(yù)清理 :并發(fā)預(yù)清理階段仍然是并發(fā)的琉朽。在這個階段毒租,虛擬機(jī)查找在執(zhí)行并發(fā)標(biāo)記階段新進(jìn)入老年代的對象(可能會有一些對象從新生代晉升到老年代, 或者有一些對象被分配到老年代)箱叁。通過重新掃描蝌衔,減少下一個階段”重新標(biāo)記”的工作,因為下一個階段會Stop The World蝌蹂。
重新標(biāo)記 :這個階段會暫停虛擬機(jī),收集器線程掃描在CMS堆中剩余的對象曹锨。掃描從”跟對象”開始向下追溯孤个,并處理對象關(guān)聯(lián)。
并發(fā)清理 :清理垃圾對象沛简,這個階段收集器線程和應(yīng)用程序線程并發(fā)執(zhí)行齐鲤。


image.png

3.CMS缺點
CMS回收器采用的基礎(chǔ)算法是Mark-Sweep。所有CMS不會整理椒楣、壓縮堆空間给郊。這樣就會有一個問題:經(jīng)過CMS收集的堆會產(chǎn)生空間碎片。 CMS不對堆空間整理壓縮節(jié)約了垃圾回收的停頓時間捧灰,但也帶來的堆空間的浪費(fèi)淆九。為了解決堆空間浪費(fèi)問題,CMS回收器不再采用簡單的指針指向一塊可用堆空 間來為下次對象分配使用。而是把一些未分配的空間匯總成一個列表炭庙,當(dāng)JVM分配對象空間的時候饲窿,會搜索這個列表找到足夠大的空間來hold住這個對象。
需要更多的CPU資源焕蹄。從上面的圖可以看到逾雄,為了讓應(yīng)用程序不停頓,CMS線程和應(yīng)用程序線程并發(fā)執(zhí)行腻脏,這樣就需要有更多的CPU鸦泳,單純靠線程切 換是不靠譜的。并且永品,重新標(biāo)記階段做鹰,為空保證STW快速完成,也要用到更多的甚至所有的CPU資源腐碱。當(dāng)然誊垢,多核多CPU也是未來的趨勢!
CMS的另一個缺點是它需要更大的堆空間症见。因為CMS標(biāo)記階段應(yīng)用程序的線程還是在執(zhí)行的喂走,那么就會有堆空間繼續(xù)分配的情況,為了保證在CMS回 收完堆之前還有空間分配給正在運(yùn)行的應(yīng)用程序谋作,必須預(yù)留一部分空間芋肠。也就是說,CMS不會在老年代滿的時候才開始收集遵蚜。相反帖池,它會嘗試更早的開始收集,已 避免上面提到的情況:在回收完成之前吭净,堆沒有足夠空間分配睡汹!默認(rèn)當(dāng)老年代使用68%的時候,CMS就開始行動了寂殉。 – XX:CMSInitiatingOccupancyFraction =n 來設(shè)置這個閥值囚巴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市友扰,隨后出現(xiàn)的幾起案子彤叉,更是在濱河造成了極大的恐慌,老刑警劉巖村怪,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秽浇,死亡現(xiàn)場離奇詭異,居然都是意外死亡甚负,警方通過查閱死者的電腦和手機(jī)柬焕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門审残,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人击喂,你說我怎么就攤上這事维苔。” “怎么了懂昂?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵介时,是天一觀的道長。 經(jīng)常有香客問我凌彬,道長沸柔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任铲敛,我火速辦了婚禮褐澎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伐蒋。我一直安慰自己工三,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布先鱼。 她就那樣靜靜地躺著俭正,像睡著了一般。 火紅的嫁衣襯著肌膚如雪焙畔。 梳的紋絲不亂的頭發(fā)上掸读,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機(jī)與錄音宏多,去河邊找鬼儿惫。 笑死,一個胖子當(dāng)著我的面吹牛伸但,可吹牛的內(nèi)容都是我干的肾请。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼更胖,長吁一口氣:“原來是場噩夢啊……” “哼筐喳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起函喉,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荣月,沒想到半個月后管呵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡哺窄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年捐下,在試婚紗的時候發(fā)現(xiàn)自己被綠了账锹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡坷襟,死狀恐怖奸柬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婴程,我是刑警寧澤廓奕,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站档叔,受9級特大地震影響桌粉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衙四,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一铃肯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧传蹈,春花似錦押逼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至表锻,卻和暖如春恕齐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞬逊。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工显歧, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人确镊。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓士骤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蕾域。 傳聞我的和親對象是個殘疾皇子拷肌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容