整理幾個重要的Java知識,幹貨分享

程序員火花塞 2021-09-19 06:10:08 阅读数:462

整理 重要 java 分享

直擊面試

反正我是帶著這些問題往下讀的

  • 說一下 JVM 運行時數據區吧,都有哪些區?分別是幹什麼的?
  • Java 8 的內存分代改進
  • 舉例棧溢出的情况?
  • 調整棧大小,就能保存不出現溢出嗎?
  • 分配的棧內存越大越好嗎?
  • 垃圾回收是否會涉及到虛擬機棧?
  • 方法中定義的局部變量是否線程安全?

運行時數據區

內存是非常重要的系統資源,是硬盤和 CPU 的中間倉庫及橋梁,承載著操作系統和應用程序的實時運行。JVM 內存布局規定了 Java 在運行過程中內存申請、分配、管理的策略,保證了 JVM 的高效穩定運行。不同的 JVM 對於內存的劃分方式和管理機制存在著部分差异。

下圖是 JVM 整體架構,中間部分就是 Java 虛擬機定義的各種運行時數據區域。

整理幾個重要的Java知識,幹貨分享_程序員

jvm-framework

Java 虛擬機定義了若幹種程序運行期間會使用到的運行時數據區,其中有一些會隨著虛擬機啟動而創建,隨著虛擬機退出而銷毀。另外一些則是與線程一一對應的,這些與線程一一對應的數據區域會隨著線程開始和結束而創建和銷毀。

  • 線程私有:程序計數器、棧、本地棧
  • 線程共享:堆、堆外內存(永久代或元空間、代碼緩存)

下面我們就來一一解毒下這些內存區域,先從最簡單的入手

一、程序計數器

程序計數寄存器(Program Counter Register),Register 的命名源於 CPU 的寄存器,寄存器存儲指令相關的線程信息,CPU 只有把數據裝載到寄存器才能够運行。

這裏,並非是廣義上所指的物理寄存器,叫程序計數器(或PC計數器或指令計數器)會更加貼切,並且也不容易引起一些不必要的誤會。JVM 中的 PC 寄存器是對物理 PC 寄存器的一種抽象模擬

程序計數器是一塊較小的內存空間,可以看作是當前線程所執行的字節碼的行號指示器

1.1 作用

PC 寄存器用來存儲指向下一條指令的地址,即將要執行的指令代碼。由執行引擎讀取下一條指令。

整理幾個重要的Java知識,幹貨分享_程序員_02

jvm-pc-counter

(分析:進入class文件所在目錄,執行javap -v xx.class反解析(或者通過IDEA插件Jclasslib直接查看,上圖),可以看到當前類對應的Code區(匯編指令)、本地變量錶、异常錶和代碼行偏移量映射錶、常量池等信息。)

1.2 概述

  • 它是一塊很小的內存空間,幾乎可以忽略不計。也是運行速度最快的存儲區域
  • 在 JVM 規範中,每個線程都有它自己的程序計數器,是線程私有的,生命周期與線程的生命周期一致
  • 任何時間一個線程都只有一個方法在執行,也就是所謂的當前方法。如果當前線程正在執行的是 Java 方法,程序計數器記錄的是 JVM 字節碼指令地址,如果是執行 natice 方法,則是未指定值(undefined)
  • 它是程序控制流的指示器,分支、循環、跳轉、异常處理、線程恢複等基礎功能都需要依賴這個計數器來完成
  • 字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令
  • 它是唯一一個在 JVM 規範中沒有規定任何 OutOfMemoryError 情况的區域

:使用PC寄存器存儲字節碼指令地址有什麼用呢?為什麼使用PC寄存器記錄當前線程的執行地址呢?

*?:因為CPU需要不停的切換各個線程,這時候切換回來以後,就得知道接著從哪開始繼續執行。JVM的字節碼解釋器就需要通過改變PC寄存器的值來明確下一條應該執行什麼樣的字節碼指令。

:PC寄存器為什麼會被設定為線程私有的?

*?:多線程在一個特定的時間段內只會執行其中某一個線程方法,CPU會不停的做任務切換,這樣必然會導致經常中斷或恢複。為了能够准確的記錄各個線程正在執行的當前字節碼指令地址,所以為每個線程都分配了一個PC寄存器,每個線程都獨立計算,不會互相影響。


二、虛擬機棧

2.1 概述

Java 虛擬機棧(Java Virtual Machine Stacks),早期也叫 Java 棧。每個線程在創建的時候都會創建一個虛擬機棧,其內部保存一個個的棧幀(Stack Frame),對應著一次次 Java 方法調用,是線程私有的,生命周期和線程一致。

作用:主管 Java 程序的運行,它保存方法的局部變量、部分結果,並參與方法的調用和返回。

特點:

  • 棧是一種快速有效的分配存儲方式,訪問速度僅次於程序計數器
  • JVM 直接對虛擬機棧的操作只有兩個:每個方法執行,伴隨著入棧(進棧/壓棧),方法執行結束出棧
  • 棧不存在垃圾回收問題

棧中可能出現的异常:

Java 虛擬機規範允許?Java虛擬機棧的大小是動態的或者是固定不變的

  • 如果采用固定大小的 Java 虛擬機棧,那每個線程的 Java 虛擬機棧容量可以在線程創建的時候獨立選定。如果線程請求分配的棧容量超過 Java 虛擬機棧允許的最大容量,Java 虛擬機將會拋出一個?StackOverflowError?异常
  • 如果 Java 虛擬機棧可以動態擴展,並且在嘗試擴展的時候無法申請到足够的內存,或者在創建新的線程時沒有足够的內存去創建對應的虛擬機棧,那 Java 虛擬機將會拋出一個OutOfMemoryError异常

可以通過參數-Xss來設置線程的最大棧空間,棧的大小直接决定了函數調用的最大可達深度。

2.2 棧的存儲單比特

棧中存儲什麼?

  • 每個線程都有自己的棧,棧中的數據都是以棧幀(Stack Frame)的格式存在
  • 在這個線程上正在執行的每個方法都各自有對應的一個棧幀
  • 棧幀是一個內存區塊,是一個數據集,維系著方法執行過程中的各種數據信息

2.3 棧運行原理

  • JVM 直接對 Java 棧的操作只有兩個,對棧幀的壓棧出棧,遵循“先進後出/後進先出”原則
  • 在一條活動線程中,一個時間點上,只會有一個活動的棧幀。即只有當前正在執行的方法的棧幀(棧頂棧幀)是有效的,這個棧幀被稱為當前棧幀(Current Frame),與當前棧幀對應的方法就是當前方法(Current Method),定義這個方法的類就是當前類(Current Class)
  • 執行引擎運行的所有字節碼指令只針對當前棧幀進行操作
  • 如果在該方法中調用了其他方法,對應的新的棧幀會被創建出來,放在棧的頂端,稱為新的當前棧幀
  • 不同線程中所包含的棧幀是不允許存在相互引用的,即不可能在一個棧幀中引用另外一個線程的棧幀
  • 如果當前方法調用了其他方法,方法返回之際,當前棧幀會傳回此方法的執行結果給前一個棧幀,接著,虛擬機會丟弃當前棧幀,使得前一個棧幀重新成為當前棧幀
  • Java 方法有兩種返回函數的方式,一種是正常的函數返回,使用 return 指令,另一種是拋出异常,不管用哪種方式,都會導致棧幀被彈出

最後

光給面試題不給答案不是我的風格。這裏面的面試題也只是鳳毛麟角,還有答案的話會極大的增加文章的篇幅,减少文章的可讀性

 CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】

Java面試寶典2021版

整理幾個重要的Java知識,幹貨分享_Java_03

整理幾個重要的Java知識,幹貨分享_後端_04

最常見Java面試題解析(2021最新版)

整理幾個重要的Java知識,幹貨分享_程序員_05

整理幾個重要的Java知識,幹貨分享_後端_06

2021企業Java面試題精選

整理幾個重要的Java知識,幹貨分享_後端_07

整理幾個重要的Java知識,幹貨分享_Java_08

版权声明:本文为[程序員火花塞]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210919061007683G.html