一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Java開發(fā)之虛擬機八股文分享

 IT小白在線 2021-11-05

簡述JVM內(nèi)存模型

線程私有的運行時數(shù)據(jù)區(qū): 程序計數(shù)器、Java 虛擬機棧、本地方法棧。

線程共享的運行時數(shù)據(jù)區(qū):Java 堆、方法區(qū)。

簡述程序計數(shù)器

程序計數(shù)器表示當前線程所執(zhí)行的字節(jié)碼的行號指示器。

程序計數(shù)器不會產(chǎn)生StackOverflowError和OutOfMemoryError。

簡述虛擬機棧

Java 虛擬機棧用來描述 Java 方法執(zhí)行的內(nèi)存模型。線程創(chuàng)建時就會分配一個??臻g,線程結(jié)束后棧空間被回收。

棧中元素用于支持虛擬機進行方法調(diào)用,每個java培訓(xùn)方法在執(zhí)行時都會創(chuàng)建一個棧幀存儲方法的局部變量表、操作棧、動態(tài)鏈接和返回地址等信息。

虛擬機棧會產(chǎn)生兩類異常:

StackOverflowError:線程請求的棧深度大于虛擬機允許的深度拋出。

OutOfMemoryError:如果 JVM 棧容量可以動態(tài)擴展,虛擬機棧占用內(nèi)存超出拋出。

簡述本地方法棧

本地方法棧與虛擬機棧作用相似,不同的是虛擬機棧為虛擬機執(zhí)行 Java 方法服務(wù),本地方法棧為本地方法服務(wù)??梢詫⑻摂M機棧看作普通的java函數(shù)對應(yīng)的內(nèi)存模型,本地方法??醋饔蒼ative關(guān)鍵詞修飾的函數(shù)對應(yīng)的內(nèi)存模型。

本地方法棧會產(chǎn)生兩類異常:

StackOverflowError:線程請求的棧深度大于虛擬機允許的深度拋出。

OutOfMemoryError:如果 JVM 棧容量可以動態(tài)擴展,虛擬機棧占用內(nèi)存超出拋出。

簡述JVM中的堆

堆主要作用是存放對象實例,Java 里幾乎所有對象實例都在堆分配內(nèi)存,堆也是內(nèi)存管理中最大的一塊。Java的垃圾回收主要就是針對堆這一區(qū)域進行??赏ㄟ^ -Xms 和 -Xmx 設(shè)置堆的最小和最大容量。

堆會拋出 OutOfMemoryError異常。

簡述方法區(qū)

方法區(qū)用于存儲被虛擬機加載的類信息、常量、靜態(tài)變量等數(shù)據(jù)。

JDK6之前使用永久代實現(xiàn)方法區(qū),容易內(nèi)存溢出。JDK7 把放在永久代的字符串常量池、靜態(tài)變量等移出,JDK8 中拋棄永久代,改用在本地內(nèi)存中實現(xiàn)的元空間來實現(xiàn)方法區(qū),把 JDK 7 中永久代內(nèi)容移到元空間。

方法區(qū)會拋出 OutOfMemoryError異常。

簡述運行時常量池

運行時常量池存放常量池表,用于存放編譯器生成的各種字面量與符號引用。一般除了保存 Class 文件中描述的符號引用外,還會把符號引用翻譯的直接引用也存儲在運行時常量池。除此之外,也會存放字符串基本類型。

JDK8之前,放在方法區(qū),大小受限于方法區(qū)。JDK8將運行時常量池存放堆中。

簡述直接內(nèi)存

直接內(nèi)存也稱為堆外內(nèi)存,就是把內(nèi)存對象分配在JVM堆外的內(nèi)存區(qū)域。這部分內(nèi)存不是虛擬機管理,而是由操作系統(tǒng)來管理。Java通過通過DriectByteBuffer對其進行操作,避免了在 Java 堆和 Native堆來回復(fù)制數(shù)據(jù)。

簡述java創(chuàng)建對象的過程

  1. 檢查該指令的參數(shù)能否在常量池中定位到一個類的符號引用,并檢查引用代表的類是否已被加載、解析和初始化,如果沒有就先執(zhí)行類加載。

  2. 通過檢查通過后虛擬機將為新生對象分配內(nèi)存。

  3. 完成內(nèi)存分配后虛擬機將成員變量設(shè)為零值

  4. 設(shè)置對象頭,包括哈希碼、GC 信息、鎖信息、對象所屬類的類元信息等。

  5. 執(zhí)行 init 方法,初始化成員變量,執(zhí)行實例化代碼塊,調(diào)用類的構(gòu)造方法,并把堆內(nèi)對象的首地址賦值給引用變量。

簡述JVM給對象分配內(nèi)存的策略

  1. 指針碰撞:這種方式在內(nèi)存中放一個指針作為分界指示器將使用過的內(nèi)存放在一邊,空閑的放在另一邊,通過指針挪動完成分配。

  2. 空閑列表:對于 Java 堆內(nèi)存不規(guī)整的情況,虛擬機必須維護一個列表記錄哪些內(nèi)存可用,在分配時從列表中找到一塊足夠大的空間劃分給對象并更新列表記錄。

java對象內(nèi)存分配是如何保證線程安全的

  1. 對分配內(nèi)存空間采用CAS機制,配合失敗重試的方式保證更新操作的原子性。該方式效率低。

  2. 每個線程在Java堆中預(yù)先分配一小塊內(nèi)存,然后再給對象分配內(nèi)存的時候,直接在自己這塊"私有"內(nèi)存中分配。一般采用這種策略。

簡述對象的內(nèi)存布局

對象在堆內(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ù)倍,因此需要對齊填充。

如何判斷對象是否是垃圾

引用計數(shù)法:設(shè)置引用計數(shù)器,對象被引用計數(shù)器加 1,引用失效時計數(shù)器減 1,如果計數(shù)器為 0 則被標記為垃圾。會存在對象間循環(huán)引用的問題,一般不使用這種方法。

可達性分析:通過 GC Roots 的根對象作為起始節(jié)點,從這些節(jié)點開始,根據(jù)引用關(guān)系向下搜索,如果某個對象沒有被搜到,則會被標記為垃圾??勺鳛?GC Roots 的對象包括虛擬機棧和本地方法棧中引用的對象、類靜態(tài)屬性引用的對象、常量引用的對象。

簡述java的引用類型

強引用:被強引用關(guān)聯(lián)的對象不會被回收。一般采用 new 方法創(chuàng)建強引用。

軟引用:被軟引用關(guān)聯(lián)的對象只有在內(nèi)存不夠的情況下才會被回收。一般采用 SoftReference 類來創(chuàng)建軟引用。

弱引用:垃圾收集器碰到即回收,也就是說它只能存活到下一次垃圾回收發(fā)生之前。一般采用 WeakReference 類來創(chuàng)建弱引用。

虛引用:無法通過該引用獲取對象。唯一目的就是為了能在對象被回收時收到一個系統(tǒng)通知。虛引用必須與引用隊列聯(lián)合使用。

簡述標記清除算法、標記整理算法和標記復(fù)制算法

標記清除算法:先標記需清除的對象,之后統(tǒng)一回收。這種方法效率不高,會產(chǎn)生大量不連續(xù)的碎片。

標記整理算法:先標記存活對象,然后讓所有存活對象向一端移動,之后清理端邊界以外的內(nèi)存

標記復(fù)制算法:將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中一塊。當使用的這塊空間用完了,就將存活對象復(fù)制到另一塊,再把已使用過的內(nèi)存空間一次清理掉。

簡述分代收集算法

根據(jù)對象存活周期將內(nèi)存劃分為幾塊,不同塊采用適當?shù)氖占惴āR话銓⒍逊譃樾律屠夏甏?,對這兩塊采用不同的算法。新生代使用:標記復(fù)制算法

老年代使用:標記清除或者標記整理算法

簡述Serial垃圾收集器

單線程串行收集器。垃圾回收的時候,必須暫停其他所有線程。新生代使用標記復(fù)制算法,老年代使用標記整理算法。簡單高效。

簡述ParNew垃圾收集器

可以看作Serial垃圾收集器的多線程版本,新生代使用標記復(fù)制算法,老年代使用標記整理算法。

簡述Parallel Scavenge垃圾收集器

注重吞吐量,即cpu運行代碼時間/cpu耗時總時間(cpu運行代碼時間+ 垃圾回收時間)。新生代使用標記復(fù)制算法,老年代使用標記整理算法。

簡述CMS垃圾收集器

注重最短時間停頓。CMS垃圾收集器為最早提出的并發(fā)收集器,垃圾收集線程與用戶線程同時工作。采用標記清除算法。該收集器分為初始標記、并發(fā)標記、并發(fā)預(yù)清理、并發(fā)清除、并發(fā)重置這么幾個步驟。

初始標記:暫停其他線程(stop the world),標記與GC roots直接關(guān)聯(lián)的對象。并發(fā)標記:可達性分析過程(程序不會停頓)。

并發(fā)預(yù)清理:查找執(zhí)行并發(fā)標記階段從年輕代晉升到老年代的對象,重新標記,暫停虛擬機(stop the world)掃描CMS堆中剩余對象。

并發(fā)清除:清理垃圾對象,(程序不會停頓)。

并發(fā)重置,重置CMS收集器的數(shù)據(jù)結(jié)構(gòu)。

簡述G1垃圾收集器

和之前收集器不同,該垃圾收集器把堆劃分成多個大小相等的獨立區(qū)域(Region),新生代和老年代不再物理隔離。通過引入 Region 的概念,從而將原來的一整塊內(nèi)存空間劃分成多個的小空間,使得每個小空間可以單獨進行垃圾回收。

初始標記:標記與GC roots直接關(guān)聯(lián)的對象。

并發(fā)標記:可達性分析。

最終標記,對并發(fā)標記過程中,用戶線程修改的對象再次標記一下。

篩選回收:對各個Region的回收價值和成本進行排序,然后根據(jù)用戶所期望的GC停頓時間制定回收計劃并回收。

簡述Minor GC

Minor GC指發(fā)生在新生代的垃圾收集,因為 Java 對象大多存活時間短,所以 Minor GC 非常頻繁,一般回收速度也比較快。

簡述Full GC

Full GC 是清理整個堆空間—包括年輕代和永久代。調(diào)用System.gc(),老年代空間不足,空間分配擔保失敗,永生代空間不足會產(chǎn)生full gc。

常見內(nèi)存分配策略

大多數(shù)情況下對象在新生代 Eden 區(qū)分配,當 Eden 沒有足夠空間時將發(fā)起一次 Minor GC。

大對象需要大量連續(xù)內(nèi)存空間,直接進入老年代區(qū)分配。

如果經(jīng)歷過第一次 Minor GC 仍然存活且能被 Survivor 容納,該對象就會被移動到 Survivor 中并將年齡設(shè)置為 1,并且每熬過一次 Minor GC 年齡就加 1 ,當增加到一定程度(默認15)就會被晉升到老年代。

如果在 Survivor 中相同年齡所有對象大小的總和大于 Survivor 的一半,年齡不小于該年齡的對象就可以直接進入老年代。

空間分配擔保。MinorGC 前虛擬機必須檢查老年代最大可用連續(xù)空間是否大于新生代對象總空間,如果滿足則說明這次 Minor GC 確定安全。如果不,JVM會查看HandlePromotionFailure 參數(shù)是否允許擔保失敗,如果允許會繼續(xù)檢查老年代最大可用連續(xù)空間是否大于歷次晉升老年代對象的平均大小,如果滿足將Minor GC,否則改成一次 FullGC。

簡述JVM類加載過程

加載:

  1. 通過全類名獲取類的二進制字節(jié)流.

  2. 將類的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。

  3. 在內(nèi)存中生成類的Class對象,作為方法區(qū)數(shù)據(jù)的入口。

驗證:對文件格式,元數(shù)據(jù),字節(jié)碼,符號引用等驗證正確性。

準備:在方法區(qū)內(nèi)為類變量分配內(nèi)存并設(shè)置為0值。

解析:將符號引用轉(zhuǎn)化為直接引用。

初始化:執(zhí)行類構(gòu)造器clinit方法,真正初始化。

簡述JVM中的類加載器

BootstrapClassLoader啟動類加載器:加載/lib下的jar包和類。C++編寫。

ExtensionClassLoader擴展類加載器:/lib/ext目錄下的jar包和類。java編寫。

AppClassLoader應(yīng)用類加載器,加載當前classPath下的jar包和類。java編寫。

簡述雙親委派機制

一個類加載器收到類加載請求之后,首先判斷當前類是否被加載過。已經(jīng)被加載的類會直接返回,如果沒有被加載,首先將類加載請求轉(zhuǎn)發(fā)給父類加載器,一直轉(zhuǎn)發(fā)到啟動類加載器,只有當父類加載器無法完成時才嘗試自己加載。

加載類順序:BootstrapClassLoader->ExtensionClassLoader->AppClassLoader->CustomClassLoader 檢查類是否加載順序:CustomClassLoader->AppClassLoader->ExtensionClassLoader->BootstrapClassLoader

雙親委派機制的優(yōu)點

  1. 避免類的重復(fù)加載。相同的類被不同的類加載器加載會產(chǎn)生不同的類,雙親委派保證了java程序的穩(wěn)定運行。

  2. 保證核心API不被修改。

如何破壞雙親委派機制

重載loadClass()方法,即自定義類加載器。

如何構(gòu)建自定義類加載器

  1. 新建自定義類繼承自java.lang.ClassLoader

  2. 重寫findClass、loadClass、defineClass方法

JVM常見調(diào)優(yōu)參數(shù)

  • -Xms 初始堆大小

  • -Xmx 最大堆大小

  • -XX:NewSize 年輕代大小

  • -XX:MaxNewSize 年輕代最大值

  • -XX:PermSize 永生代初始值

  • -XX:MaxPermSize 永生代最大值

  • -XX:NewRatio 新生代與老年代的比例

調(diào)用system.gc()一定會發(fā)生垃圾收集嗎?為什么?

調(diào)用System.gc()的時候,其實并不會馬上進行垃圾回收,只會把這次gc請求記錄下來。需配合System.runFinalization()才會進行真正回收

靜態(tài)變量存儲位置

在1.8以前,靜態(tài)成員變量存在方法區(qū),在1.8后,由于JDK8取消永生代,靜態(tài)變量存儲到了堆中。

內(nèi)存溢出和內(nèi)存泄漏

內(nèi)存溢出:程序在申請內(nèi)存時,此時已用內(nèi)存過多,沒有足夠的剩余內(nèi)存空間供其使用。

內(nèi)存泄漏:程序在申請內(nèi)存后,不能完全釋放已申請的內(nèi)存空間。

垃圾收集器種類:

串行收集器:Serial,Serial Old 并行收集器:Parallel Scavenge,Parallel Old 并發(fā)收集器:CMS,G1

作者:后端技術(shù)小牛說

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美日韩免费黄片观看| 麻豆视传媒短视频免费观看| 国产成人精品一区二三区在线观看| 亚洲少妇人妻一区二区| 中文字幕精品少妇人妻| 色综合视频一区二区观看| 风韵人妻丰满熟妇老熟女av| 久草热视频这里只有精品| 樱井知香黑人一区二区| 99在线视频精品免费播放| 亚洲三级视频在线观看免费| 九九九热在线免费视频| 国产又黄又猛又粗又爽的片| 91久久精品中文内射| 99精品国产一区二区青青| 草草草草在线观看视频| 国产午夜精品亚洲精品国产| 日韩在线视频精品中文字幕| 成人区人妻精品一区二区三区| 欧美一级黄片欧美精品| 日韩在线中文字幕不卡| 男生和女生哪个更好色| 在线免费国产一区二区| 欧美激情中文字幕综合八区| 青青操成人免费在线视频| 国产一区欧美一区二区| 日本高清视频在线播放| 狠狠亚洲丁香综合久久| 亚洲中文字幕熟女丝袜久久| 欧美日韩亚洲综合国产人 | 国产在线不卡中文字幕| 国产在线一区中文字幕| 日韩午夜福利高清在线观看| 91人妻人人澡人人人人精品| 国语对白刺激高潮在线视频| 欧美成人黄色一级视频| 国产美女精品午夜福利视频| 最新午夜福利视频偷拍| 精品一区二区三区人妻视频| 东京热一二三区在线免| 激情三级在线观看视频|