<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          三天刷完《深入JVM虛擬機 第三版》是什么感覺

          共 6115字,需瀏覽 13分鐘

           ·

          2021-08-10 09:38

          好久沒有寫過原創(chuàng)了,這篇是2021的第一篇原創(chuàng),最近也比較忙,項目上線,需求有非常的趕,經(jīng)歷了一次C端、pc端、B端三端從需求到上線不到一個月的時間,現(xiàn)在c端也在試運營的期間,項目上線后就稍微沒那么忙,bug比較少就會輕松一點,所以又開始自己的原創(chuàng)之路了。

          今天分享一個最近刷完的一本書《深入JVM虛擬機 第三版》,一共花了三天的時間刷完,我相信應(yīng)該很多人還沒看過,畢竟七百多頁,堅持看完真不容易,在這里分享一下自己刷完的一些經(jīng)驗,以及怎么去刷這本書。

          其實在刷這本書之前其實對于這本書的很多內(nèi)容都已經(jīng)學(xué)過了,所以再來刷這本書算是知識點的回顧吧,看的也比較快,更有目的性,在此之前對于JVM的學(xué)習(xí),我還專門的做了自己的學(xué)習(xí)和總結(jié)了自己的思維導(dǎo)圖:



          我個人的自我學(xué)習(xí)和總結(jié)都是圍著調(diào)優(yōu)的目的去的,所以再刷這本書的目的就是很簡單:讓自己對JVM的調(diào)優(yōu)有更深的理解。

          這個思維導(dǎo)圖也積累了非常久,大概一年多的時間吧,我還記得我第一看 《深入JVM虛擬機》 的時候,都是蒙蒙的,第一次也是沒有看完。

          后來因為工作需要零零散散的學(xué)了很多關(guān)于JVM的知識點,并且把它記錄下來,這就成了我最后的這個思維導(dǎo)圖,我感覺對于調(diào)優(yōu)方面的話算是比較全的了。

          下面我們開始我們的刷書之旅,先來看看這本書的總的目錄,一共五大部分,首先第一大部門直接可以略過,是不是賊開心,一秒間就少了一大部分:

          還有就是第五部分,因為這部分屬于并發(fā)編程的內(nèi)容,而且里面的內(nèi)容基本我以前的原創(chuàng)博文都寫過,所以這部分的內(nèi)容我是之間花了一小時的時間看完。

          這部分內(nèi)容其實可以不用看的,在《并發(fā)編程實戰(zhàn)》這本書里面都會有,我下一本就是打算刷《并發(fā)編程實戰(zhàn)》,大家也可以直接略過,這不又少了一部分。

          還有就是第四部分,這部分應(yīng)該是選看,我個人主要關(guān)注的是即時編譯器,因為即時編譯器還是挺重要的,有些面試也會被問到,其他部分我都是草草的看一下大致的內(nèi)容,也并不是自己想要的,因為你去看,你也記不住,并且實際中也用不到,至少是現(xiàn)在階段用不到,面試被問幾乎為0。

          還有就是第三部分,第三部分也是選看,例如第三部分的第六章,他講的是一個class文件的結(jié)構(gòu),,從二進制給你講起,你記得住嗎,完全記不住啊,還有各種字節(jié)碼指令,這不影響你看書的心情和信心嘛。

          舉個例子,下圖是第三部分第六章的內(nèi)容,他會帶你一個一個去看class文件,每一個位置分別表示什么意思,你覺得你看完這個你能記住多少,不出一天全歸零,所以這部分直接就可以略過。

          但是第三部分的類加載子系統(tǒng)就是非常重要的,包括里面的類加載過程,典型的三層類加載器、自定義類加載器、雙親委派機制,這是我們需要關(guān)注的,我之前面試字節(jié)的時候,一面就被問到類加載過程以及雙親委派機制,這個肯定也是重點。

          但是,如果大家伙的目和我的目的一樣的話關(guān)注點是在調(diào)優(yōu),其實你的重點就是在第二部分,這部分是要你摸透的。

          接下來,我們來看第二部分就是JVM的內(nèi)存管理,也就是內(nèi)存模型、運行時數(shù)據(jù)區(qū)的內(nèi)容,還有就是用于觀察JVM內(nèi)存的監(jiān)控工具,其實這部分的內(nèi)存模型應(yīng)該是很多技術(shù)博主,都寫過的博文,所以感覺大家看這部分內(nèi)容應(yīng)該算是只是的回顧了:

          第二章內(nèi)容重點是講解Java的運行時數(shù)據(jù)區(qū)、Java對象、OOM異常,其中運行時數(shù)據(jù)區(qū)大家都很熟悉了,就是這幾部分:

          • 程序計數(shù)器
          • Java虛擬機棧
          • 本地方法棧
          • Java堆
          • 方法區(qū)
          • 運行時常量池
          • 直接內(nèi)存

          這里要掌握的就是這幾個區(qū)域的含義,哪些是線程私有的,哪些是線程共有的,哪些會導(dǎo)致OOM異常出現(xiàn),帶著這幾個問題去看基本沒什么太大問題。

          直接內(nèi)存可能是有些人會比較陌生,直接內(nèi)存并不是虛擬機的一部分,他是本地內(nèi)存,按照常理來說他的大小和出現(xiàn)OOM問題之和本地內(nèi)存有關(guān),你也可以通過 -XX:MaxDirectMemorySize 參數(shù)來設(shè)置它的大小。

          與這部分內(nèi)存有關(guān)系的Java框架之一就是Netty,因為Netty的底層使用的是NIO,是給予通道緩沖區(qū)的IO方式,它通過一個DirectByteBuffer 對象來對這塊內(nèi)存進行操作。

          接下來就是對象的創(chuàng)建、對象內(nèi)存布局、對象的訪問三部分,神奇的Java是怎么通過一個new關(guān)鍵字,把對象創(chuàng)建出來的,在對象的創(chuàng)建部分,主要涉及到這幾個概念:指針碰撞、本地線程分配緩沖(Thread Local AllocationBuffer,TLAB)。

          對象是怎么分配內(nèi)存的?怎么避免多線程時內(nèi)存資源的爭搶?在哪里分配內(nèi)存(堆、棧)?這塊的內(nèi)容基本就是圍繞這幾個問題講解。

          對象創(chuàng)建出來后并且分配內(nèi)存后,對象在內(nèi)存中又是怎么布局的,我相信大家可能之前看過一篇文章說:XX大廠XX面,面試官:你知道Java中對象有多大嗎?

          一個對象分為幾部分(對象頭(Header)、實例 數(shù)據(jù)(Instance Data)和對齊填充(Padding)),以及對象頭(Mark Word)里面又包含那些內(nèi)容等等諸如此類的問題,你都可以這部分找到答案。

          最后就是對象的訪問:句柄、直接指針。這兩種方式有什么區(qū)別?分別有什么缺點和優(yōu)點?搞懂這幾個問題,就算是掌握了90%以上了。

          以上的內(nèi)容都是偏理論的,理論總是為實戰(zhàn)服務(wù)的,后面的OOM異常就是偏實戰(zhàn)的,前面介紹的幾個運行時數(shù)據(jù)區(qū)除了程序計數(shù)器不會出現(xiàn)OOM,其他的部分都有可能會出現(xiàn)OOM。

          而除了程序計數(shù)器不用考慮外(以下調(diào)優(yōu)可以直接忽略程序計數(shù)器),在JVM中Java堆是調(diào)優(yōu)的最重要也是最難的一部分,基本上JVM中的調(diào)優(yōu)參數(shù)復(fù)雜的都是偏向于Java堆,對于除了Java堆其它的運行時數(shù)據(jù)期出現(xiàn)OOM的解決辦法是啥?最有效的辦法就是適當(dāng)?shù)脑龃髢?nèi)存。

          而Java堆的調(diào)優(yōu)就不是偏偏的增大內(nèi)存那么簡單,有時Java堆增大堆存,反而會適得其反,因為雖然內(nèi)存大了,可能新生代的可分配的對象數(shù)量也增多了,但是單次GC的回收時間也變得長了,這樣會導(dǎo)致系統(tǒng)卡頓時間增長。

          對于那些用戶交互時間頻繁,要求響應(yīng)時間短的應(yīng)用,就不能接受了,可能老板就是找你:兔崽子,上次是不是你調(diào)優(yōu)的JVM,現(xiàn)在卡頓的時間又更長了,用戶每天投訴,你今晚必須搞定,不然明天別來了。

          所以Java堆也是調(diào)優(yōu)一塊的重點和難點,首先在這部分先了解和熟悉分別各個區(qū)域出現(xiàn)OOM異常后,打印出來的堆棧信息一般都是怎么樣的,比如堆OOM就如下所示:

          java.lang.OutOfMemoryError: Java heap space
          Dumping heap to java_pid3404.hprof ...
          Heap dump file created [22045981 bytes in 0.663 secs]

          在堆棧信息中都能看到“Java heap space”這個名稱,還有就是那些場景會導(dǎo)致這幾部分的內(nèi)存溢出呢?這個也是比較重要的,比如遞歸深度過大、方法過長,程序中出現(xiàn)大對象,內(nèi)存泄露,線程池數(shù)量設(shè)置不合理,過度使用代理、常量數(shù)量過多過大、Class信息過多等都會分別導(dǎo)致那些區(qū)域OOM呢?

          其實對于調(diào)優(yōu)之前還有要說清楚的就是,可能百分之七八十的問題,都可以通過代碼優(yōu)化來解決,比如方法過長,方法拆一下不就行了嘛,出現(xiàn)大對象,創(chuàng)建小一點的對象不就行了嘛。

          但是,有時候有些問題你就有可能忽略掉,比如大對象(有可能是同一時間內(nèi)多對象),盡管你在開發(fā)中都非常的小心翼翼了,對象已經(jīng)控制的非常小了,在生產(chǎn)中流量一上來的就出現(xiàn)OOM了,只有生產(chǎn)的流量才有可能驗證你的某一些被忽略的功能。

          舉個例子,在PC端都有會有一個導(dǎo)出的功能,有當(dāng)前頁的導(dǎo)出以及全部的導(dǎo)出,特別是這個全部的導(dǎo)出,數(shù)據(jù)量小的時候就沒啥問題,要是數(shù)據(jù)量一大,以及流量一上來,那同一時間內(nèi)創(chuàng)建的Excell對象就非常的多,一不小心就出現(xiàn)OOM了。

          再比如,面向用戶的C端首頁,一般C端首頁為了提高用戶的體驗度都會進行緩存,那么當(dāng)緩存的數(shù)量過大,同一時間從緩存里面獲取的對象就會過多或者對象過大的問題。

          對于這部分的內(nèi)容,我之前的思維導(dǎo)圖,也是做了非常詳細的總結(jié),以下只是其中的一部分,大家可以作為參看,對于大家思考也是非常重要的。

          接下來第三章就是圍繞著GC來講解,針對調(diào)優(yōu)的區(qū)域就是Java堆,包括怎么判斷對象是否存活(引用計數(shù)法、可達性分析算法),三種基本的垃圾收集算法(標(biāo)記-清楚、復(fù)制算法、標(biāo)記-整理),分代模型理論(新生代、老年代),以及常用的經(jīng)典垃圾收集器、搭配,適用場景。搞懂這些問題,你就無敵了,這部分的內(nèi)容你就吃透了

          其中經(jīng)典垃圾收集器大家是比較陌生的,其他部分像垃圾收集算法、分代模型理論、判斷對象是否存活,很多技術(shù)博主都有寫過,垃圾收集算法我之前也寫過一篇原創(chuàng),大家可以參考一下。

          我們重點來關(guān)注一下垃圾收集器,隨著jdk的不斷發(fā)展,版本的不斷升級,服務(wù)器由單核演變多核,內(nèi)存的變大,垃圾收集器也變得越來越智能,每種垃圾收集器都有自己的適用場景。

          這幾種垃圾收集器比較常見的搭配如下圖所示:

          我個人記憶比較深的搭配就是:

          • SerialSerial Old
          • PSPO
          • ParNewCMS
          • G1

          每種垃圾收集器都有自己的使用場景,優(yōu)點和缺點,所以再看這部分的內(nèi)容就帶著這幾個問題去看就行了:

          • 年輕代和老年代分別的垃圾收集器是什么?
          • 每種垃圾收集器的優(yōu)點和缺點?
          • 每種垃圾收集器的使用場景?
          • 每種垃圾收集器的原理?
          • 每種垃圾收集器的JVM的相關(guān)設(shè)置參數(shù)是啥?

          把這幾個問題搞懂基本也就摸透了,比如在適用于單核時代的Serial收集器它的主要問題一個就是造成了STW的問題,以及單線程的垃圾回收效率問題,但是對于單核的服務(wù)器,它無疑是最佳的選擇。

          以及后面發(fā)展到多線程時代PS和PO,由原來的的單線程收集,現(xiàn)在編程了多線程收集,肯定是比原來垃圾收集的時間效率提高了,但是對于多線程又有設(shè)置回收垃圾的線程數(shù)是多少,書中都有給出建議的。

          后面比較經(jīng)典的就是CMS,CMS有分為四個階段初始標(biāo)記、并發(fā)標(biāo)記、重新標(biāo)記、并發(fā)清理。

          這四個階段的原理又是啥,那些階段的與用戶線程并發(fā)操作的,CMS又是怎么最大程度減少STW問題的,CMS一般適用于的堆大小范圍是多少等等。

          對于這些問題的答案相應(yīng)的部分都說的明明白白的,大家可以仔細研究,后面一個就是G1,前面經(jīng)典的垃圾收集器都是給予分代模型的。

          但是,分代模型又是有自己存在的問題,比如經(jīng)典的分代垃圾收集器相對應(yīng)的都是整個堆大小的收集,隨著服務(wù)器性能的提高,服務(wù)器的內(nèi)存也會越來越大,現(xiàn)在動不動就好幾個g或者10幾個g的大小,那么這樣就會導(dǎo)致單次的垃圾收集時間越來越長,停頓的時間也會相應(yīng)變長,因為STW現(xiàn)在位置是沒辦法消除的,只能盡可能的減少。

          這也就是后面出現(xiàn)了G1,G1弱化了分代理論模型的垃圾收集,改為整個堆劃分為一個一個Region,每個Region都不是固定的哪一個代(新生代、老年代),在發(fā)生垃圾回收的時候,G1會對每一個Region的回收耗時做記錄,這樣就可以統(tǒng)計出要回收的成本,所以G1做到了在用戶可接受的停頓時間(STW,一般100-300毫秒)的時間范圍進行垃圾收集,不用針對整個堆。

          以上就是G1來帶來的優(yōu)勢,解決傳統(tǒng)的垃圾收集器出現(xiàn)的問題,但是G1本身自己還存在問題,比如會產(chǎn)生浮動垃圾,這個是G1至今未解決的問題,還有G1在極端的情況下可能會造成系統(tǒng)假死的現(xiàn)象。

          這也是為什么現(xiàn)在垃圾默認(rèn)的垃圾收集器還不是G1的一些原因,這些問題都可以在文中找到,這部分的內(nèi)容一定要細細的品,仔細的琢磨。

          其中還有兩款面向低延時的收集器是,我們現(xiàn)在階段暫時用不到,你去看一下它使用的場景就知道了,以及適用于Java堆大小,所以大家可以忽略:

          當(dāng)然你有興趣的話,也可以細細品讀,畢竟是大佬寫出來的東西,吸收了就都是精華。

          熟悉和精通上面集中垃圾收集的原理后,下面就是實戰(zhàn)了,我這邊我在我的思維導(dǎo)圖里面總解決常用的JVM調(diào)優(yōu)參數(shù):

          當(dāng)然書籍里面也有,不過比較零散,我這邊基本都已經(jīng)總結(jié)好了。

          接下來就是實戰(zhàn)部分包括一些場景和原則:對象內(nèi)存的分配原則、大對象、長期存活的對象、對象年齡、空間的分配擔(dān)保,這部分的內(nèi)容也一定要細細的品,肯定是精華。

          第四章的就是調(diào)優(yōu)的工具了,對于工具,我自己使用的是jdk自帶的VisualVM,它可以配置到idea中,并且可以安裝GC插件和其他的插件,非常的方便,不過他一般是本地或者測試環(huán)境使用,像線上的工具我推薦的是使用阿里的Arthas工具,百度有一堆的教程。

          還有就是比較原始的排查方法,使用linux命令,例如jps、jstat、jinfo、jmap、jstack,這部分在書上有詳細的講解:

          對于這些原始命令的使用,主要有兩個考點,也是兩個實戰(zhàn)點,分別是:分析cpu飆高的問題、分析OOM的問題。還有另一個就是分析內(nèi)存不足的問題,這個就比較簡單。

          假如你都能夠使用上面的原始命令和分析工具對以上問題能夠自己獨立分析,那你就是無敵了,調(diào)優(yōu)高手啊,老板還不得花重金請你。

          大家也可以參考一下我自己的思維導(dǎo)圖,方式都差不多,大差不差,但還不完整,因為有些還沒整理:

          第五章部分,我感覺大家可以略過,可能是大佬的經(jīng)歷和我們不一樣,實戰(zhàn)的場景,很少遇見過,我是直接跳過的。

          到這里要是以上的內(nèi)容都吃透的話,后面的內(nèi)容基本就是純理論的東西,對你來說也不難:

          第三部分就直接看虛擬機的加載機制,包括類加載過程、經(jīng)典的三層加載器、自定義類加載器、雙親委派等,這些就是這部分的重點。

          這部分搞懂了可以寫寫代碼怎么去實現(xiàn)自己的類加載器,加載自己的類,怎么去破壞雙親委派模型,諸如此類的問題,文章里面都有講解。

          好了到這里基本我個人需要的內(nèi)容已經(jīng)吸收的差不多了,我就是帶著調(diào)優(yōu)的目的去看這本書的,這里澄清一下不是說不看的內(nèi)容說寫的不好,不是這樣的,只是我們是帶著目的去學(xué)習(xí)的,書里的內(nèi)容很詳細,但是并不是所有的東西都是我們需要的,至少是現(xiàn)階段,我只是幫大家把我們需要的內(nèi)容提取出來,然后分享自己刷這本書的目的以及經(jīng)驗。

          限于篇幅,后面會繼續(xù)分享自己對于JVM虛擬機的深入的學(xué)習(xí)和了解,有需要 《深入JVM虛擬機第三版》 電子書可以添加我微信:abc730500468,那本書重點的部分我都打上了標(biāo)記,便于你們刷,以及刷的過程有技術(shù)可以相互討論,好了我是黎杜,我們下一期見。

          推薦閱讀:
          MySQL 開源工具集合
          什么是布隆過濾器?如何解決高并發(fā)緩存穿透問題?
          如何通過Binlog來實現(xiàn)不同系統(tǒng)間數(shù)據(jù)同步
          高并發(fā)服務(wù)優(yōu)化篇:詳解RPC的一次調(diào)用過程
          如何設(shè)計一個高性能的秒殺系統(tǒng)

          關(guān)互聯(lián)網(wǎng)全棧架構(gòu)。


          瀏覽 39
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜怡红院 | 欧美精品综合 | 亚洲精品色哟哟 | 很很撸AV | 欧美手机精品在线 |