【JavaEE初階】-- JVM

文章目錄

  • 1. JVM運行流程
  • 2. Java運行時數據區
    • 2.1 方法區(內存共享)
    • 2.2 堆(內存共享)
    • 2.3 Java虛擬機棧(線程私有)
    • 2.4 本地方法棧(線程私有)
    • 2.5 程序計數器(線程私有)
  • 3. JVM 類加載
    • 3.1 類加載的過程
      • 3.1.1 加載
      • 3.1.2 驗證
      • 3.1.3 準備
      • 3.1.4 解析
      • 3.1.5 初始化
      • 3.1.6 使用
      • 3.1.8卸載
    • 3.2 雙親委派模型
      • 3.2.1 什么是雙親委派模型
      • 3.2.2 破壞雙親委派模型
  • 4. 垃圾回收
    • 4.1 死亡對象的判斷方法
      • 4.1.1 引用計數算法
      • 4.1.2 可達性分析算法(JVM使用的算法)
    • 4.2 垃圾回收算法
      • 4.2.1 標記-清除算法
      • 4.2.2 復制算法
      • 4.2.3 標記-整理算法
        • 4.2.4 分代法
    • 4.3 垃圾收集器
      • 4.3.1 Serial收集器(新生代收集器,串行GC)
      • 4.3.2 ParNew收集器(新生代收集器,并行GC)
      • 4.3.3 CMS 收集器(標記-清楚算法)

JVM就是Java虛擬機。虛擬機是指通過軟件虛擬出來的具有完整硬件功能的計算機系統,它的運行環境是完全隔離的。

我們知道Java是一個跨平臺的語言,可以不加修改的在任何操作系統中運行,這就是依托于其運行在JVM中實現的。

1. JVM運行流程

  1. .java 文件 被編譯成 .class 文件,。
  2. 通過 類加載子系統 將 .class 二進制字節碼文件加載到內存中。
  3. 方法區保存類對象,類對象是new對象的模板。
  4. new出來的對象全都放在堆內存中。
  5. 每個線程都會在Java虛擬機棧中分配一個與之對應的內存空間,棧中存放是是線程對方法的調用層級。
  6. 本地方法棧中存放的是本地方法的調用層級。
  7. 程序計數器,保存的是當前線程執行的行號。
    在這里插入圖片描述

2. Java運行時數據區

在這里插入圖片描述

2.1 方法區(內存共享)

方法區保存的是類的類對象,這個類對象就是我們在new對象時的模板。由于存放的是類對象,是公共的數據,所以方法區是線程共享的,所以線程都可以訪問這個區域。

在JDK7的實現中被稱為永久代。
在JDK8的實現中被稱為元空間。

2.2 堆(內存共享)

所有new出來的對象都存放在堆中。堆是JVM內存中使用最大的內存區域,默認占內存的八分之一,不過這個比例是可以JVM參數設置進行設置的。

2.3 Java虛擬機棧(線程私有)

每創建一個線程就會在內存中創建一個與之對應的Java虛擬機棧。Java虛擬機棧的生命周期和線程是相同的,線程結束,對應的Java虛擬機棧就會被垃圾回收掉。

在這個Java虛擬機棧中,調用一個方法就會將該方法壓入棧,此時我們將其成為棧幀,當方法執行完之后就會出棧,知道這個棧中的棧幀全部出棧,此時就代表著棧空了,也就意味線程結束了。

在這里插入圖片描述

2.4 本地方法棧(線程私有)

調用本地方法時使用的棧,記錄本地方法的調用層級。

2.5 程序計數器(線程私有)

我們知道多個線程在CPU上是搶占式執行的。那么線程重新調度到CPU上怎么知道上一次執行到了什么地方呢,就是通過程序計數器來記錄的。

3. JVM 類加載

3.1 類加載的過程

在這里插入圖片描述

3.1.1 加載

  1. 通過類的全限定名來獲取定義此類的二進制字節流。
  2. 將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
  3. 在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口。

3.1.2 驗證

驗證.class文件是否符合JVM規范。
JVM17規范
在這里插入圖片描述

3.1.3 準備

比如我們定義了一個常量count。
java public static int count = 100;
在準備階段僅僅是給count分配一個內存空間,并給設置其初始值,就想count,其設置的初始值是0。

3.1.4 解析

將常量池內的符號引用替換為直接引用的過程。也就是把字節碼中的符號引用和真實的內存進行了解析關聯。

3.1.5 初始化

執行代碼中的真正的賦值操作。

3.1.6 使用

使用階段就是new對象的過程,執行構造方法,以及父類的構造方法,初始化完成之后一個對象就創建出來了。

3.1.8卸載

程序停止時從jvm中卸載。

3.2 雙親委派模型

使用哪個類加載器進行加載類的過程。

3.2.1 什么是雙親委派模型

在這里插入圖片描述

  1. 當我們創建一個類時,先從應用程序加載器開始向上轉發,一直轉發到啟動類加載器。
  2. 類啟動加載器在自己的路徑下找,看有沒有要創建的這個類,有則加載,沒有就繼續向下轉發到擴展加載器。
  3. 擴展加載器在自己的路徑下找,看有沒有要創建的這個類,有則加載,沒有就繼續向下轉發到應用程序加載器。
  4. 應用程序加載器在自己的路徑中找到類并加載。

3.2.2 破壞雙親委派模型

JDBC就是一個典型的案例。
在這里插入圖片描述

這段源碼的說明的翻譯:返回此線程的上下文類加載器。該上下文類加載器由線程的創建者提供,供在此線程中運行的代碼在加載類和資源時使用。如果未設置,則默認值為父線程的類加載器上下文。原始線程的上下文類加載器通常設置為用于加載應用程序的類加載器。 返回值:此線程的上下文類加載器,若無則返回 null,表示系統類加載器(若上述情況均不成立,則返回引導類加載器) 異常情況:如果存在安全管理者,并且調用者的類加載器不為空且與上下文類加載器不同或不是其祖先,同時調用者未擁有“getClassLoader”這一運行時權限,則會拋出 SecurityException 異常。

Java平臺里面自身定義了一套API訪問接口,數據庫廠商需要實現這個API,廠商實現了這個接口之后會自己提供的一些jar包,供用戶來使用。

比如我們使用的是MySQL,DriveManager 調用getConnection,getConnection并不知道要使用MySQL,這里就自己指定了自己要用的加載器,使用的是當前線程的上下文問的加載器,此時就破壞了雙親委派模型機制,在加載類時并沒有向上傳遞,而是直接指定了相應的加載器。

4. 垃圾回收

垃圾回收的是對象占用的內存空間,主要說的是堆內存。程序計數器、虛擬機棧、本地方法棧都是和線程同生同死。

4.1 死亡對象的判斷方法

4.1.1 引用計數算法

給每一個對象增加一個引用計數器,每當一個地方引用了該對象時,引用計數器就加一,引用失效時,就減一。當引用計數器為0時,就代表該對象死亡了,是可被回收的。

引用計數法實現較簡單,判斷效率也比較高,但是引用計數法無法解決循環引用的問題 會導致出現內存泄露的情況。

循環依賴的例子:

public class Test {public Object instance = null;private static int _1MB = 1024 * 1024;private byte[] bigSize = new byte[2 * _1MB];public static void testGC() {Test test1 = new Test();Test test2 = new Test();test1.instance = test2;test2.instance = test1;test1 = null;test2 = null;
// 強制jvm進?垃圾回收System.gc();}public static void main(String[] args) {testGC();}
}

JVM并未采用這種方法,但是python使用的是這種算法。

4.1.2 可達性分析算法(JVM使用的算法)

通過以一系列的GC-root的對象作為起始點,從起始點開始向下進行搜索,搜索時走過等我路線,就是引用鏈,當一個對象沒有在任何一個引用鏈上,就表示該對象是不可用的,就會被標記為可回收。那么在下次垃圾回收的時候就會被回收掉。
在這里插入圖片描述
在Java語言中,可作為GC Roots的對象包含下面幾種:

  1. 虛擬機棧(棧幀中的本地變量表)中引?的對象;
  2. 方法區中類靜態屬性引?的對象;
  3. 方法區中常量引?的對象;
  4. 本地方法棧中 JNI(Native?法)引?的對象。

4.2 垃圾回收算法

4.2.1 標記-清除算法

  1. JVM會根據可達性分析算法來標記可回收的內存區域。
  2. 對標記可回收的內存區域進行回收。
    在這里插入圖片描述

但是標記-清除算法會使內存區域變得很分散 如果此時進來了一個大對象,將會沒有足夠的空間進行存儲,此時就會觸發垃圾回收,如果垃圾回收之后還沒有足夠的空間進行存儲,還會再次進行垃圾回收,一直這樣操作,直到有足夠大的空間能夠存儲這個大對象。

當進行垃圾回收的時候,會停止所有的線程STW,這個停止的時間是沒有辦法控制的,這是非常危險的。

4.2.2 復制算法

這種算法會將內存區域分成兩個部分,我們稱為內存區域一和內存區域二。程序運行的時候只使用一個內存區域,另一個內存區域是空閑的。

在這里插入圖片描述

  1. 把內存區域一中存儲的對象,復制到內存區域二中。
  2. 在內存區域二中把對象按內存地址順序排列好,相當于對內存進行了整理。
  3. 把內存區域一的空間全部清空。
  4. 每次回收都重復上述工作。

但是這種算法的內存利用率不高。

4.2.3 標記-整理算法

標記整理算法和復制算法一樣,但是標記整理算法不是將可回收對象進行清理,而是將存活對象向內存的一邊緣移動,然后清除掉邊緣以外的內存區域。

在這里插入圖片描述

4.2.4 分代法

分代法是將內存分為兩個區域:新生代 和 老年代,這兩個區域的默認比例是1:2。

在這里插入圖片描述

新生代使用的復制算法,老年代使用的是標記整理算法。

新生代中存放的是剛new出來的對象,老年代中存放的是經過多次GC(默認是15次),也沒有被回收掉的對象。

新生代的內存區域又被分為Eden區和s1區、s2區 這個比例默認是8:1:1。

垃圾回收的過程:

  1. 所有的新 new的對象都會存放在新生代的Eden區。
    在這里插入圖片描述

  2. 當Eden區滿了之后,就會觸發一輪GC,如果對象沒有被回收將會被復制到FROM區,然后把Eden區內存全部清空。
    在這里插入圖片描述

  3. 當觸發下一次GC時,會將FROM區和Eden區仍然存活的對象復制到TO區。

  4. 接下來就是s1 和 s2進行呼喚from 和 to區,重復上面的步驟。

  5. 如果經歷了一輪GC對象沒有被回收掉,年齡 +1,如果年齡超過15歲(默認是15 ,但是可以進行設置),年齡保存在對象頭中。

  6. 如果對象的年齡超過15歲就會被移入老年代。

如果一個很大的對象被創建,Eden區放不下怎么辦??
會嘗試將該對象直接放入老年代。

以上的所有比例都是可以設置的!!!

4.3 垃圾收集器

垃圾收集器是對垃圾回收算法的具體實現。

在這里插入圖片描述

4.3.1 Serial收集器(新生代收集器,串行GC)

Serial收集器是虛擬機運行在Client模式下的默認新生代收集器。

與其他收集器相比,該收集器簡單而高效(原因:由于是單線程的,沒有線程交互的開銷)。
在這里插入圖片描述

4.3.2 ParNew收集器(新生代收集器,并行GC)

它是Serial收集器的多線程版本。

ParNew收集器是許多運行在Server模式下的虛擬機中首選的新生代收集器。

在這里插入圖片描述

4.3.3 CMS 收集器(標記-清楚算法)

CMS(Concurrent Mark Sweep)收集器是?種以獲取最短回收停頓時間為目標的收集器。

CMS的運行過程:

  1. 初始標記:標記一下GC Roots 能直接關聯到的對象,速度很快,需要STW(為什么?因為保證在標記開始時,引用關系不會發生變化)。
  2. 并發標記:從“初始標記”的對象開始,并發的便利整個對象圖,標記所有可達對象。整個操作是和用戶線程并發進行的,所以對象的引用關系可能會發生變化。
  3. 重新標記:會STW,修正并發標記期間,因用戶程序繼續運行而導致標記產生變動的那一部分。
  4. 并發清除:和用戶進程并發進行,清除掉在標記階段判斷為死亡的對象。
    在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96351.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96351.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96351.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第十四屆藍橋杯青少組C++選拔賽[2023.1.15]第二部分編程題(4 、移動石子)

參考程序1&#xff1a;#include <bits/stdc.h> using namespace std; int main() {int N;cin >> N;vector<int> stones(N);int sum 0;for (int i 0; i < N; i) {cin >> stones[i];sum stones[i];}int target sum / N; // 每個籃子的平均值int a…

Spring Boot 的注解是如何生效的

在 Spring 中&#xff0c;Configuration、ComponentScan、Bean、Import 等注解的掃描、解析和 BeanDefinition 注冊是一個分層處理的過程。下面我們以 Configuration 類為例&#xff0c;結合代碼流程詳細說明其從掃描到注冊的完整邏輯。 1. 整體流程概覽 以下是核心步驟的流程圖…

Django REST Framework響應類Response詳解

概述 Response 類是一個智能的 HTTP 響應類&#xff0c;能夠根據客戶端請求的內容類型&#xff08;Content-Type&#xff09;自動將數據渲染成合適的格式&#xff08;JSON、XML、HTML等&#xff09;。 基本用法 from rest_framework.response import Response# 最簡單的用法 de…

# 小程序 Web 登錄流程完整解析

登錄流程完整小白解析&#xff08;小程序 & Web&#xff09; 在開發中&#xff0c;登錄是每個系統最基礎的功能。為了讓小白也能理解&#xff0c;我們用通俗類比和流程講解 小程序登錄、Web 登錄、Token 刷新、安全存儲等整個過程。1?? 小程序登錄流程&#xff08;小白理…

安裝vcenter6.7 第二階段安裝很慢 或卡在50%

DNS、FQDN配置的問題采用VCSA安裝vCenter時&#xff0c;第一步安裝還算順利&#xff0c;第二步就會安裝失敗&#xff0c;而且還特別慢&#xff0c;這是因為部署時需要DNS服務器&#xff0c;下面就是不采用DNS服務器的部署方案。第一步&#xff1a;正常安裝&#xff0c;DNS就寫本…

第十六屆藍橋杯軟件賽 C 組省賽 C++ 題解

大家好&#xff0c;今天是 2025 年 9 月 11 日&#xff0c;我來給大家寫一篇關于第十六屆藍橋杯軟件賽 C 組省賽的C 題解&#xff0c;希望對大家有所幫助&#xff01;&#xff01;&#xff01; 創作不易&#xff0c;別忘了一鍵三連 題目一&#xff1a;數位倍數 題目鏈接&…

項目幫助文檔的實現

項目幫助文檔的實現 代碼如下&#xff1a; #ifndef __M_HELPER_H__ #define __M_HELPER_H__ #include <iostream> #include <fstream> #include <string> #include <vector> #include <sqlite3.h> #include <random> #include <sstream…

python逆向-逆向pyinstaller打包的exe程序反編譯獲取源代碼

python逆向-逆向pyinstaller打包的exe程序反編譯獲取源代碼 Pyinstaller pyinstaller 是一個用于將 Python 程序打包成獨立可執行文件的工具&#xff0c;能夠在沒有 Python 解釋器的情況下運行。 Python 腳本轉換為 Windows、macOS 和 Linux 操作系統上的可執行文件。 把Python…

【SQL】-- sql having 和 where 的 區別

HAVING 和 WHERE 都是用來篩選數據的&#xff0c;但它們的應用場景有所不同。WHERE&#xff1a;用于篩選行數據&#xff0c;通常在 FROM 子句之后執行。它在分組操作 (GROUP BY) 之前應用&#xff0c;用來篩選出符合條件的記錄。示例&#xff1a;SELECT name, age FROM employe…

MySQL,SQL Server,PostgreSQL三種數據庫各自的優缺點,分別適用哪些場景

MySQL的優缺點及適用場景優點開源免費&#xff0c;社區版可商用&#xff0c;成本低。輕量級&#xff0c;安裝配置簡單&#xff0c;適合中小型項目。讀寫性能優異&#xff0c;尤其在OLTP&#xff08;在線事務處理&#xff09;場景下表現突出。支持主從復制、分片等擴展方案&…

Java 類加載機制雙親委派與自定義類加載器

我們來深入解析 Java 類加載機制。這是理解 Java 應用如何運行、如何實現插件化、以及解決一些依賴沖突問題的關鍵。一、核心概念&#xff1a;類加載過程一個類型&#xff08;包括類和接口&#xff09;從被加載到虛擬機內存開始&#xff0c;到卸載出內存為止&#xff0c;它的整…

Kaggle項目實踐——Titanic: Machine Learning from Disaster

泰坦尼克號沉船事件是機器學習領域最經典的入門項目之一。Kaggle 上的 Titanic: Machine Learning from Disaster 競賽&#xff0c;被無數人稱為“機器學習的 Hello World”。 一、數據導入與清洗&#xff1a;讓數據從 “雜亂” 變 “干凈” 機器學習模型就像 “挑食的孩子”…

Qt C++ 復雜界面處理:巧用覆蓋層突破復雜界面處理難題?之二

接上一篇&#xff0c;繼續探索“覆蓋層”的使用方法。 五、覆蓋層進階交互&#xff1a;從 “能繪制” 到 “好操作”? 基礎的繪制功能只能滿足 “看得見” 的需求&#xff0c;實際開發中還需要 “能操作”—— 比如選中線條修改顏色、按 Delete 鍵刪除線條、鼠標 hover 時高亮…

神經網絡構成框架-理論學習

一、神經網絡的基本組成與分類 1.1 神經網絡的核心組成部分 神經網絡是現代人工智能的基石&#xff0c;其設計靈感來源于生物神經系統的信息處理方式。作為工程師&#xff0c;了解神經網絡的基本組成部分對于構建和優化模型至關重要。一個典型的神經網絡主要由以下幾個關鍵部分…

從0開始開發app(AI助手版)-架構及環境搭建

架構選擇 前端React Native 后端Firebase 原因 環境準備 安裝node 安裝JDK 命令行工具&#xff1a;Node.js command prompt命令行查詢Javav版本&#xff1a;javac -version使用nrm工具切換淘寶源&#xff1a;npx nrm use taobao安裝yarn&#xff0c;替代npm下載工具&#x…

【性能測試】Jmeter工具快速上手-搭建壓力測試腳本

&#x1f525;個人主頁&#xff1a; 中草藥 &#x1f525;專欄&#xff1a;【Java】登神長階 史詩般的Java成神之路 概念 性能測試是軟件測試的重要分支&#xff0c;核心目標是通過模擬真實業務場景和負載壓力&#xff0c;評估系統在不同條件下的性能表現&#xff0c;發現系統性…

oracle里的int類型

oracle里的int類型 在 ANSI SQL 標準 中&#xff0c;INTEGER 和 SMALLINT 是定義好的精確數值類型&#xff0c;但它們的 “長度”或“大小”并不是通過 (N) 括號來指定的&#xff08;如 INT(4)&#xff09;&#xff0c;這一點與 MySQL 等數據庫的非標準擴展完全不同。 SMALLI…

前端學習之后端java小白(二)-sql約束/建表

一、約束SQL約束&#xff08;Constraints&#xff09;是用于限制表中數據的規則&#xff0c;確保數據的完整性和準確性。以下是主要的SQL約束類型&#xff1a; 主要約束類型&#xff1a; 1. NOT NULL 約束: 確保列不能包含空值 CREATE TABLE users (id INT NOT NULL,name VARC…

OpenCV:圖像金字塔

文章目錄一、什么是圖像金字塔&#xff1f;二、圖像金字塔的核心操作&#xff1a;采樣與逆采樣1. 向下采樣&#xff08;pyrDown&#xff09;&#xff1a;從高分辨率到低分辨率步驟1&#xff1a;高斯濾波步驟2&#xff1a;刪除偶數行與偶數列OpenCV實戰代碼效果特點2. 向上采樣&…

LVS與Keepalived詳解(一)負載均衡集群介紹

文章目錄前言一、什么是LVS&#xff1f;二、四層&#xff08;L4&#xff09;負載均衡的最佳解決方案是什么&#xff1f;2.1解決方案分類與對比&#xff08;負載均衡的三種方式介紹&#xff09;2.1.1 硬件負載均衡 (Hardware Load Balancer)2.1.2 軟件負載均衡 (Software Load B…