您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java虛擬機常見面試題”,在日常操作中,相信很多人在Java虛擬機常見面試題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java虛擬機常見面試題”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
我堅信,機會永遠屬于有準備的人,我們與其羨慕他人的成功,不如從此刻起,積累足夠多的知識和面試經驗,為將來進入更好的公司做好充分的準備!想讓面試官在短短的幾十分鐘內認可你的能力?想在最短的時間內收獲 Java 技術棧最核心的知識點?想要更全面更深入的了解 Java 技術?這篇文章給你想要的所有答案。
小編分享的這份Java后端開發面試總結包含了JavaOOP、Java集合容器、Java異常、并發編程、Java反射、Java序列化、JVM、Redis、Spring MVC、MyBatis、MySQL數據庫、消息中間件MQ、Dubbo、Linux、ZooKeeper、 分布式&數據結構與算法等26個專題技術點,都是小編在各個大廠總結出來的面試真題,已經有很多粉絲靠這份PDF拿下眾多大廠的offer,今天在這里總結分享給到大家!【已完結】
完整版Java面試題地址:2021最新面試題合集集錦。
序號 | 專題 | 內容 | 鏈接 |
---|---|---|---|
1 | 中間件 | Java中間件面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5012470 |
2 | 微服務 | Java微服務面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5014045 |
3 | 并發編程 | Java并發編程面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5017511 |
4 | Java基礎 | Java基礎知識面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5020008 |
5 | Spring Boot | Spring Boot面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5021192 |
6 | Redis | Redis面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5022120 |
7 | Spring MVC | Spring MVC面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5022126 |
8 | Spring Cloud | Spring Cloud面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5023319 |
9 | MySQL優化 | MySQL優化面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5023320 |
10 | JVM | JVM性能調優面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5023321 |
11 | Linux | Linux面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5025281 |
12 | Mybatis | Mybatis面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5025282 |
13 | 網絡編程 | TCP,UDP,Socket,Http網絡編程面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5025284 |
14 | 設計模式 | 設計模式面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5033946 |
15 | 大數據 | 大數據面試題100道(2021最新版) | https://my.oschina.net/u/4678580/blog/5037399 |
16 | Tomcat | Tomcat面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5034995 |
17 | 多線程 | 多線程面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5036124 |
18 | Nginx | Nginx_BIO_NIO_AIO面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5037626 |
19 | memcache | memcache面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5033471 |
20 | java異常 | java異常面試題(2021最新版) | https://my.oschina.net/u/4678580/blog/5038814 |
21 | Java虛擬機 | Java虛擬機面試題(2021最新版) | 持續更新中! |
22 | Java集合 | Java集合面試題(2021最新版) | 持續更新中! |
23 | Git常用命令 | Git常用命令(2021最新版) | 持續更新中! |
24 | Elasticsearch | Elasticsearch面試題(2021最新版) | 持續更新中! |
25 | Dubbo | Dubbo面試題(2021最新版) | 持續更新中! |
這個夸平臺是中間語言(JVM)實現的夸平臺
Java有JVM從軟件層面屏蔽了底層硬件、指令層面的細節讓他兼容各種系統
Jdk包括了Jre和Jvm,Jre包括了Jvm
Jdk是我們編寫代碼使用的開發工具包
Jre 是Java的運行時環境,他大部分都是 C 和 C++ 語言編寫的,他是我們在編譯java時所需要的基礎的類庫
Jvm俗稱Java虛擬機,他是java運行環境的一部分,它虛構出來的一臺計算機,在通過在實際的計算機上仿真模擬各種計算機功能來實現Java應用程序
看Java官方的圖片,Jdk中包括了Jre,Jre中包括了JVM
Java 虛擬機在執行 Java 程序的過程中會把它所管理的內存區域劃分為若干個不同的數據區域。這些區域都有各自的用途,以及創建和銷毀的時間,有些區域隨著虛擬機進程的啟動而存在,有些區域則是依賴線程的啟動和結束而建立和銷毀。Java 虛擬機所管理的內存被劃分為如下幾個區域:
程序計數器(Program Counter Register):當前線程所執行的字節碼的行號指示器,字節碼解析器的工作是通過改變這個計數器的值,來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能,都需要依賴這個計數器來完成;為什么要線程計數器?因為線程是不具備記憶功能
Java 虛擬機棧(Java Virtual Machine Stacks):每個方法在執行的同時都會在Java 虛擬機棧中創建一個棧幀(Stack Frame)用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息;棧幀就是Java虛擬機棧中的下一個單位
本地方法棧(Native Method Stack):與虛擬機棧的作用是一樣的,只不過虛擬機棧是服務 Java方法的,而本地方法棧是為虛擬機調用 Native 方法服務的;
Native 關鍵字修飾的方法是看不到的,Native 方法的源碼大部分都是 C和C++ 的代碼
Java 堆(Java Heap):Java 虛擬機中內存最大的一塊,是被所有線程共享的,幾乎所有的對象實例都在這里分配內存;
方法區(Methed Area):用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯后的代碼等數據。
Java虛擬機是線程私有的,它的生命周期和線程相同。
虛擬機棧描述的是Java方法執行的內存模型: 每個方法在執行的同時 都會創建一個棧幀(Stack Frame)用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。
解釋:虛擬機棧中是有單位的,單位就是棧幀,一個方法一個棧幀。一個棧幀中他又要存儲,局部變量,操作數棧,動態鏈接,出口等。
java堆(Java Heap)是java虛擬機所管理的內存中最大的一塊,是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的唯一目的就是存放對象實例。
在Java虛擬機規范中的描述是:所有的對象實例以及數組都要在堆上分配。
java堆是垃圾收集器管理的主要區域,因此也被成為“GC堆”。
從內存回收角度來看java堆可分為:新生代和老生代。
從內存分配的角度看,線程共享的Java堆中可能劃分出多個線程私有的分配緩沖區。
無論怎么劃分,都與存放內容無關,無論哪個區域,存儲的都是對象實例,進一步的劃分都是為了更好的回收內存,或者更快的分配內存。
根據Java虛擬機規范的規定,java堆可以處于物理上不連續的內存空間中。當前主流的虛擬機都是可擴展的(通過 -Xmx 和 -Xms 控制)。如果堆中沒有內存可以完成實例分配,并且堆也無法再擴展時,將會拋出OutOfMemoryError異常。
本地方法棧很好理解,他很棧很像,只不過方法上帶了 native 關鍵字的棧字
它是虛擬機棧為虛擬機執行Java方法(也就是字節碼)的服務方法
native關鍵字的方法是看不到的,必須要去oracle官網去下載才可以看的到,而且native關鍵字修飾的大部分源碼都是C和C++的代碼。
同理可得,本地方法棧中就是C和C++的代碼
方法區是所有線程共享的內存區域,它用于存儲已被Java虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。
它有個別命叫Non-Heap(非堆)。當方法區無法滿足內存分配需求時,拋出OutOfMemoryError異常。
虛擬機核心的組件就是執行引擎,它負責執行虛擬機的字節碼,一般戶先進行編譯成機器碼后執行。
“虛擬機”是一個相對于“物理機”的概念,虛擬機的字節碼是不能直接在物理機上運行的,需要JVM字節碼執行引擎- 編譯成機器碼后才可在物理機上執行。
直接內存(Direct Memory)并不是虛擬機運行時數據區的一部分,也不是Java虛擬機中定義的內存區域。但是這部分內存也被頻繁地使用,而且也可能導致 OutOfMemoryError 異常出現,所以我們放到這里一起講解。
我的理解就是直接內存是基于物理內存和Java虛擬機內存的中間內存
程序在運行過程中,會產生大量的內存垃圾(一些沒有引用指向的內存對象都屬于內存垃圾,因為這些對象已經無法訪問,程序用不了它們了,對程序而言它們已經死亡),為了確保程序運行時的性能,java虛擬機在程序運行的過程中不斷地進行自動的垃圾回收(GC)。
垃圾收集系統是Java的核心,也是不可少的,Java有一套自己進行垃圾清理的機制,開發人員無需手工清理
有一部分原因就是因為Java垃圾回收系統的強大導致Java領先市場
淺拷貝(shallowCopy)只是增加了一個指針指向已存在的內存地址,
深拷貝(deepCopy)是增加了一個指針并且申請了一個新的內存,使這個增加的指針指向這個新的內存,
淺復制:僅僅是指向被復制的內存地址,如果原地址發生改變,那么淺復制出來的對象也會相應的改變。
深復制:在計算機中開辟一塊新的內存地址用于存放復制的對象。
內存泄漏是指不再被使用的對象或者變量一直被占據在內存中。理論上來說,Java是有GC垃圾回收機制的,也就是說,不再被使用的對象,會被GC自動回收掉,自動從內存中清除。
但是,即使這樣,Java也還是存在著內存泄漏的情況,java導致內存泄露的原因很明確:長生命周期的對象持有短生命周期對象的引用就很可能發生內存泄露, 盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收 ,這就是java中內存泄露的發生場景。
在java中,程序員是不需要顯示的去釋放一個對象的內存的,而是由虛擬機自行執行。在JVM中,有一個垃圾回收線程,它是低優先級的,在正常情況下是不會執行的,只有在虛擬機空閑或者當前堆內存不足時,才會觸發執行,掃面那些沒有被任何引用的對象,并將它們添加到要回收的集合中,進行回收。
GC 是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會導致程序或系統的不穩定甚至崩潰,Java 提供的 GC 功能可以自動監測對象是否超過作用域從而達到自動回收內存的目的,Java 語言沒有提供釋放已分配內存的顯示操作方法。
優點:JVM的垃圾回收器都不需要我們手動處理無引用的對象了,這個就是最大的優點
缺點:程序員不能實時的對某個對象或所有對象調用垃圾回收器進行垃圾回收。
對于GC來說,當程序員創建對象時,GC就開始監控這個對象的地址、大小以及使用情況。
通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是"可達的",哪些對象是"不可達的"。當GC確定一些對象為"不可達"時,GC就有責任回收這些內存空間。
可以。程序員可以手動執行System.gc(),通知GC運行,但是Java語言規范并不保證GC一定會執行。
強引用:發生 gc 的時候不會被回收。
軟引用:有用但不是必須的對象,在發生內存溢出之前會被回收。
弱引用:有用但不是必須的對象,在下一次GC時會被回收。
虛引用(幽靈引用/幻影引用):無法通過虛引用獲得對象,用 PhantomReference 實現虛引用,虛引用的用途是在 gc 時返回一個通知。
清理整個堆空間—包括年輕代和老年代和永久代
因為Full GC是清理整個堆空間所以Full GC執行速度非常慢,在Java開發中最好保證少觸發Full GC
當對象對當前使用這個對象的應用程序變得不可觸及的時候,這個對象就可以被回收了。
垃圾回收不會發生在永久代,如果永久代滿了或者是超過了臨界值,會觸發完全垃圾回收(Full GC)。如果你仔細查看垃圾收集器的輸出信息,就會發現永久代也是被回收的。這就是為什么正確的永久代大小對避免Full GC是非常重要的原因。
標記-清除算法:標記無用對象,然后進行清除回收。缺點:效率不高,無法清除垃圾碎片。
復制算法:按照容量劃分二個大小相等的內存區域,當一塊用完的時候將活著的對象復制到另一塊上,然后再把已使用的內存空間一次清理掉。缺點:內存使用率不高,只有原來的一半。
標記-整理算法:標記無用對象,讓所有存活的對象都向一端移動,然后直接清除掉端邊界以外的內存。
分代算法:根據對象存活周期的不同將內存劃分為幾塊,一般是新生代和老年代,新生代基本采用復制算法,老年代采用標記整理算法。
垃圾回收不會發生在永久代,如果永久代滿了或者是超過了臨界值,會觸發完全垃圾回收(Full GC)。如果你仔細查看垃圾收集器的輸出信息,就會發現永久代也是被回收的。這就是為什么正確的永久代大小對避免Full GC是非常重要的原因。請參考下Java8:從永久代到元數據區 (注:Java8中已經移除了永久代,新加了一個叫做元數據區的native內存區)
Minor GC是新生代GC,指的是發生在新生代的垃圾收集動作。由于java對象大都是朝生夕死的,所以Minor GC非常頻繁,一般回收速度也比較快。(一般采用復制算法回收垃圾)
Major GC是老年代GC,指的是發生在老年代的GC,通常執行Major GC會連著Minor GC一起執行。Major GC的速度要比Minor GC慢的多。(可采用標記清楚法和標記整理法)
Full GC是清理整個堆空間,包括年輕代和老年代
如果沒有Survivor,Eden區每進行一次Minor GC,存活的對象就會被送到老年代。老年代很快被填滿,觸發Major GC.老年代的內存空間遠大于新生代,進行一次Full GC消耗的時間比Minor GC長得多,所以需要分為Eden和Survivor。
Survivor的存在意義,就是減少被送到老年代的對象,進而減少Full GC的發生,Survivor的預篩選保證,只有經歷15次Minor GC還能在新生代中存活的對象,才會被送到老年代。
設置兩個Survivor區最大的好處就是解決了碎片化,剛剛新建的對象在Eden中,經歷一次MinorGC,Eden中的存活對象就會被移動到第一塊survivor space S0,Eden被清空;等Eden區再滿了,就再觸發一次Minor GC,Eden和S0中的存活對象又會被復制送入第二塊survivor spaceS1(這個過程非常重要,因為這種復制算法保證了S1中來自S0和Eden兩部分的存活對象占用連續的內存空間,避免了碎片化的發生)
默認的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數 –XX:NewRatio來指定 ),即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小。
其中,新生代 ( Young ) 被細分為 Eden 和 兩個 Survivor 區域,Edem 和倆個Survivor 區域比例是 = 8 : 1 : 1 ( 可以通過參數 –XX:SurvivorRatio 來設定 ),
但是JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來為對象服務,所以無論什么時候,總是有一塊 Survivor 區域是空閑著的。
垃圾收集器是垃圾回收算法(標記清楚法、標記整理法、復制算法、分代算法)的具體實現,不同垃圾收集器、不同版本的JVM所提供的垃圾收集器可能會有很在差別。
如果說垃圾收集算法是內存回收的方法論,那么垃圾收集器就是內存回收的具體實現。下圖展示了7種作用于不同分代的收集器,其中用于回收新生代的收集器包括Serial、PraNew、Parallel Scavenge,回收老年代的收集器包括Serial Old、Parallel Old、CMS,還有用于回收整個Java堆的G1收集器。不同收集器之間的連線表示它們可以搭配使用。
Serial收集器(復制算法): 新生代單線程收集器,標記和清理都是單線程,優點是簡單高效;
ParNew收集器 (復制算法): 新生代收并行集器,實際上是Serial收集器的多線程版本,在多核CPU環境下有著比Serial更好的表現;
Parallel Scavenge收集器 (復制算法): 新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用戶線程時間/(用戶線程時間+GC線程時間),高吞吐量可以高效率的利用CPU時間,盡快完成程序的運算任務,適合后臺應用等對交互相應要求不高的場景;
Serial Old收集器 (標記-整理算法): 老年代單線程收集器,Serial收集器的老年代版本;
Parallel Old收集器 (標記-整理算法): 老年代并行收集器,吞吐量優先,Parallel Scavenge收集器的老年代版本;
CMS(Concurrent Mark Sweep)收集器(標記-清除算法): 老年代并行收集器,以獲取最短回收停頓時間為目標的收集器,具有高并發、低停頓的特點,追求最短GC回收停頓時間。
G1(Garbage First)收集器 ( 標記整理 + 復制算法來回收垃圾 ): Java堆并行收集器,G1收集器是JDK1.7提供的一個新收集器,G1收集器基于“標記-整理”算法實現,也就是說不會產生內存碎片。此外,G1收集器不同于之前的收集器的一個重要特點是:G1回收的范圍是整個Java堆(包括新生代,老年代),而前六種收集器回收的范圍僅限于新生代或老年代。
Serial / Serial Old Serial / CMS ParNew / Serial Old ParNew / CMS Parallel Scavenge / Serial Old Parallel Scavenge / Parallel Old G1
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
新生代垃圾回收器一般采用的是復制算法,復制算法的優點是效率高,缺點是內存利用率低;老年代回收器一般采用的是標記-整理的算法進行垃圾回收。
分代回收器有兩個分區:老生代和新生代,新生代默認的空間占比總空間的 1/3,老生代的默認占比是 2/3。
新生代使用的是復制算法,新生代里有 3 個分區:Eden、To Survivor、From Survivor,它們的默認占比是 8:1:1,它的執行流程如下:
把 Eden + From Survivor 存活的對象放入 To Survivor 區;
清空 Eden 和 From Survivor 分區;
From Survivor 和 To Survivor 分區交換,From Survivor 變 To Survivor,To Survivor 變
From Survivor。
每次在 From Survivor 到 To Survivor 移動時都存活的對象,年齡就 +1,當年齡到達 15(默認配置是 15)時,升級為老生代。大對象也會直接進入老生代。
老生代當空間占用到達某個值之后就會觸發全局垃圾收回,一般使用標記整理的執行算法。以上這些循環往復就構成了整個分代垃圾回收的整體執行流程。
虛擬機把描述類的數據從Class文件加載到內存,并對數據進行校驗,解析和初始化,最終形成可以被虛擬機直接使用的java類型。
程序主動使用某個類時,如果該類還未被加載到內存中,則JVM會通過加載、連接、初始化3個步驟來對該類進行初始化。如果沒有意外,JVM將會連續完成3個步驟,所以有時也把這個3個步驟統稱為類加載或類初始化。
#常用的設置
-Xms:初始堆大小,JVM 啟動的時候,給定堆空間大小。
-Xmx:最大堆大小,JVM 運行過程中,如果初始堆空間不足的時候,最大可以擴展到多少。
-Xmn:設置堆中年輕代大小。整個堆大小=年輕代大小+年老代大小+持久代大小。
-XX:NewSize=n 設置年輕代初始化大小大小
-XX:MaxNewSize=n 設置年輕代最大值
-XX:NewRatio=n 設置年輕代和年老代的比值。如: -XX:NewRatio=3,表示年輕代與年老代比值為 1:3,年輕代占整個年輕代+年老代和的 1/4
-XX:SurvivorRatio=n 年輕代中 Eden 區與兩個 Survivor 區的比值。注意 Survivor 區有兩個。8表示兩個Survivor :eden=2:8 ,即一個Survivor占年輕代的1/10,默認就為8
-Xss:設置每個線程的堆棧大小。JDK5后每個線程 Java 棧大小為 1M,以前每個線程堆棧大小為 256K。
-XX:ThreadStackSize=n 線程堆棧大小
-XX:PermSize=n 設置持久代初始值
-XX:MaxPermSize=n 設置持久代大小
-XX:MaxTenuringThreshold=n 設置年輕帶垃圾對象最大年齡。如果設置為 0 的話,則年輕代對象不經過 Survivor 區,直接進入年老代。
#下面是一些不常用的
-XX:LargePageSizeInBytes=n 設置堆內存的內存頁大小
-XX:+UseFastAccessorMethods 優化原始類型的getter方法性能
-XX:+DisableExplicitGC 禁止在運行期顯式地調用System.gc(),默認啟用
-XX:+AggressiveOpts 是否啟用JVM開發團隊最新的調優成果。例如編譯優化,偏向鎖,并行年老代收集等,jdk6紙之后默認啟動
-XX:+UseBiasedLocking 是否啟用偏向鎖,JDK6默認啟用
-Xnoclassgc 是否禁用垃圾回收
-XX:+UseThreadPriorities 使用本地線程的優先級,默認啟用
-xx:+Use xxx GC
xxx 代表垃圾收集器名稱
-XX:+UseSerialGC:設置串行收集器,年輕帶收集器
-XX:+UseParNewGC:設置年輕代為并行收集。可與 CMS 收集同時使用。JDK5.0 以上,JVM 會根據系統
配置自行設置,所以無需再設置此值。
-XX:+UseParallelGC:設置并行收集器,目標是目標是達到可控制的吞吐量
-XX:+UseParallelOldGC:設置并行年老代收集器,JDK6.0 支持對年老代并行收集。
-XX:+UseConcMarkSweepGC:設置年老代并發收集器
-XX:+UseG1GC:設置 G1 收集器,JDK1.9默認垃圾收集器
到此,關于“Java虛擬機常見面試題”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。