国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Java程序是如何運行的

張康康 ? 2019-12-27 09:31 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

JVM是Java的運行時虛擬機,所有的Java程序都是在JVM沙箱中運行,每個Java程序就是一個獨立的JVM進程。

談到Java程序是如何運行的,首先需要理解的肯定是JVM是如何運行的,什么是JVM;要理解我們編寫的Java程序,運行起來以后到底是什么樣子,本質上就是弄清楚JVM是什么樣子。

Java程序的代碼是什么樣的

Java誕生之初最大的賣點就是編寫的代碼跨平臺可移植性,實現這種可移植性,是因為Java通過平臺特定的虛擬機,運行中間的字節碼,而不是直接編譯成本地二進制代碼實現,中間字節碼也就是java文件編譯后生成的.class文件,Jar包的話,實際上只是一系列.class文件的集合。

編寫Java程序,首先需要一個入口點,在運行的時候通過指定MainClass來指定入口點,代碼層面主類必須實現一個靜態的main函數,運行時虛擬機會從MainClass.main開始執行指令,其他的邏輯只是import和函數調用了。

SDK自帶的javac命令,負責將我們編程的Java代碼,也就是.java文件,編譯成平臺無關的字節碼;字節碼可以在任何操作系統平臺上,通過平臺對應的JVM執行;JVM執行的時候,運行字節碼,根據自己的平臺特性,將字節碼轉換成平臺相關的二進制碼運行。

javac編譯器運行的過程大致分為:詞法分析(Token流)、語法分析(語法樹)、語義分析(注解語法樹),還有代碼生成器,根據注解語法樹,生成字節碼,

語義分析階段,編譯器會做一些操作,將人類友好的代碼,做一些處理,轉換成更符合機器執行機制的代碼,例如全局變量,魔法變量,依賴注入,注解這些魔法機制。大致分為以下步驟:

  1. 給類添加默認構造函數

  2. 處理注解

  3. 檢查語義的合法性并進行邏輯判斷

  4. 數據流分析

  5. 對語法樹進行語義分析(變量自動轉換并去掉語法糖)

JVM是什么

JVM = 類加載器 classloader + 執行引擎 execution engine + 運行時數據區域 runtime data area

JVM就是運行編譯好字節碼的虛擬機,不同的操作系統和平臺上,虛擬機將平臺無關的字節碼,編譯成特定平臺的指令去執行。我覺得,JVM首先是一個獨立運行在操作系統上的進程。執行java命令運行程序的時候,會啟動一個進程,每個獨立的程序就運行在一個獨立的JVM進程里。JVM負責執行字節碼,從而實現程序要完成的所有功能。

JVM主要由三部分組成:類加載器、運行時數據區和執行引擎。類加載器加載編譯好的.class文件,將所有類結構和方法變量放入運行時數據區,初始化之后,將程序的執行交給執行引擎;JIT編譯器,負責將字節碼編譯成平臺特定的二進制碼,調用本地接口庫。垃圾回收器作為執行引擎的一部分,負責維護運行時數據區中可變的應用程序內存空間。

類加載器(ClassLoader

類加載器將類加載到內存,并管理類的生命周期,知道將類從內存中卸載結束生命周期。

系統提供了三種類加載器,分別用于不同類的加載:

  1. 啟動類加載器(Bootstrap ClassLoader),該加載器會將lib目錄下能被虛擬機識別的類加載到內存中,也就是系統類

  2. 擴展類加載器(Extension ClassLoader),該加載器會將libext目錄下的類庫加載到內存

  3. 應用程序類加載器(Application ClassLoader),該加載器負責加載用戶路徑上所指定的類庫。

運行時數據區(Runtime Data Area

運行時數據區,是JVM運行時,在內存中分配的空間。

運行時數據區,被分為五個不同的結構:

  1. Java虛擬機棧(Java Stacks): 也叫棧內存,主管Java程序的運行,是在線程創建時創建,它的生命期是跟隨線程的生命期,線程結束棧內存也就釋放,對于棧來說不存在垃圾回收問題,只要線程一結束該棧就Over,生命周期和線程一致,是線程私有的。

  2. 本地方法棧(Native Method Memory): 登記的native方法,執行引擎執行時加載

  3. 程序寄存器(PC Registers): 當前線程所執行字節碼的指針,存儲每個線程下一步要執行的字節碼JVM指令。

  4. Java堆(Heap Memory): 應用的對象和數據都是存在這個區域,這塊區域也是線程共享的,也是gc 主要的回收區,一個 JVM 實例只存在一個堆類存,堆內存的大小是可以調節的。類加載器讀取了類文件后,需要把類、方法、常變量放到堆內存中,以方便執行器執行。

  5. 方法區(Method Area): 所有定義的方法的信息都保存在該區域,此區域屬于共享區間。靜態變量+常量+類信息+運行時常量池存在方法區中,實例變量存在堆內存中。

其中的程序寄存器、Java虛擬機棧是按照線程分配的,每個線程都有自己私有的獨立空間。

運行的方法和運行期數據,以棧幀的形式存儲在運行時JVM虛擬機棧中,棧幀中保存了本地變量,包括輸入輸出參數和本地變量;保存類文件和方法等幀數據,還記錄了出棧入棧操作。每一個方法被調用直至執行完成的過程就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。

堆在JVM是所有線程共享的,因此在其上進行對象內存的分配均需要進行加鎖。

執行引擎(Execution Engine

執行引擎由三個模塊組成,分別是執行引擎,JIT CompilerGarbage Collector,執行引擎的核心是Jit Compiler,執行字節碼或者本地方法;垃圾回收器,則是一系列線程,負責管理分代堆內存。

三個模塊分別是運行時計算和運行時內存的管理,負責執行運行時指令的是執行引擎,通過程序寄存器和虛擬機棧中的棧幀出入棧實現方法和指令的執行。GC則負責堆內存的管理,因為GC的時候需要停止指令的執行,消耗資源,所以采用分代方式管理對象收集。JIT則是把字節碼編譯成本地二進制代碼,并調用本地庫執行。

GC垃圾回收機制

Java的內存管理,主要是針對的堆內存,因為堆內存是運行時程序和數據分配的空間;不同于內存的其他區域,加載完程序之后,基本上可以確定需要占用的空間大小;heap memory 空間會在運行時動態的分配,無法預測,可大可小,而且快速變化,管理不慎就容易產生內存溢出,所以由JVM提供了強大的分代內存管理機制。

JVM 使用分代內存管理,來分配運行時的堆內存結構,針對不同的世代,采用不同的垃圾回收算法

常用垃圾回收算法

  • 引用計數器法(Reference Counting)

  • 標記清除法(Mark-Sweep)

  • 復制算法(Coping)

  • 標記壓縮法(Mark-Compact)

  • 分代算法(Generational Collecting)

  • 分區算法(Region)

堆內存的組成

heap 的組成有三區域/世代:分別是新生代(Young Generation)、老生代(Old Generation/tenured)和永久區(Perm)。

新生代堆內存又分成Eden區和兩個生存區,其中Eden區和生存區的占比為8:1:1,在清理新生代內存的時候,使用的是復制清除算法,優點是清除以后不會產生碎片;簡單的復制算法,將內存分成大小相同的兩個區域,每次周期只分配其中的一半,這樣空間利用率比較低,只使用了一半的內存。

考慮到新生代內存區的對象都是周期很短的,所以JVM實現了一種優化的復制算法,設置一個較大的Eden區來分配對象內存,Eden區空間不夠了觸發垃圾回收,將上一個生存區和Eden區中還存活的對象,復制到空閑的生存區。然后清空上述兩個區域,這樣就不會產生內存碎片。

將清理一定次數(15次)還生存的對象,定期晉升到老生代內存區,如果生存區空間不夠了,則馬上就會觸發晉升機制。將部分對象直接晉升到老生代。

如果晉升之后,發現老生代內存不夠,就會觸發完整的全局GC,清理老生代和新生代內存,老生代內存清理需要使用標記清除和標記整理兩種算法。

GC工作原理

分配內存的時候,首先分配到新生代的Eden區,如果Eden區滿了,就會發起一次Minor GC,將Eden和From Survivor生存的對象,拷貝到To Survivor Space,如果清理過程中,to Space的空間占用達到一定閾值,或者有對象經歷Minor GC的次數達標,就會將對象移動到老生代內存。如果移動過程中發現,老生代內存的空間已經不夠了。這時就需要發起Full GC,先進行一次Minor GC,然后通過CMS進行標記清除算法,清理老生代內存,老生代內存經歷標記清除之后,因為會產生內存碎片,還需要采用標記整理算法,將所有內存塊往前移動,形成連續的內存空間。

老生代標記清除的優點是不需要額外空間。不同于老生代清除算法,會產生碎片,而且標記算法的成本開銷也很大;在新生代清除中,因為考慮到大多數新生代對象生存期都是很短暫的,可以使用一種空間換時間的思路,拿出一部分內存空間不分配,而是作為中轉,將每次檢查時還生存的對象拷貝到Survivor Space,然后直接清除所有原區域的對象,因為大量對象都是生存周期極短的,所以Survivor Space的空間可以遠小于正常分配的空間。

不同于引用計數方法,Java使用一種 GC Roots 的對象作為起點開始檢查對象,當一個對象到 GC Roots 沒有任何引用鏈相連時, 即該對象不可達, 也就說明此對象是不可用的。就會在GC的時候收回。

GC清理類型的時候,為了防止程序地址出現異常,需要stop the world,清理線程會停止所有運行線程,直到清理完,這個時候是影響性能的。

垃圾回收器的本質

垃圾回收器在JVM層面,是由一系列不同的組件組成的,每種組件是一個獨立線程,分別執行自己的邏輯。

新生代垃圾收集器:

  1. Serial(串行)收集器是最基本、發展歷史最悠久的收集器,它是采用復制算法的新生代收集器,。它是一個單線程收集器,只會使用一個CPU或一條收集線程去完成垃圾收集工作,更重要的是它在進行垃圾收集時,必須暫停其他所有的工作線程,直至Serial收集器收集結束為止(“Stop The World”)。

  2. ParNew收集器就是Serial收集器的多線程版本,它也是一個新生代收集器。除了使用多線程進行垃圾收集外,其余行為包括Serial收集器可用的所有控制參數、收集算法(復制算法)、Stop The World、對象分配規則、回收策略等與Serial收集器完全相同,兩者共用了相當多的代碼。

  3. Parallel Scavenge收集器也是一個并行的多線程新生代收集器,它也使用復制算法。Parallel Scavenge收集器的特點是它的關注點與其他收集器不同,CMS等收集器的關注點是盡可能縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge收集器的目標是達到一個可控制的吞吐量(Throughput)。

老生代垃圾收集器:

  1. Serial Old 是Serial收集器的老年代版本,它同樣是一個單線程收集器,使用“標記-整理”(Mark-Compact)算法

  2. Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法

  3. CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器,優點是:并發收集、低停頓,因此CMS收集器也被稱為并發低停頓收集器(Concurrent Low Pause Collector)

面向服務端的G1收集器。

G1收集器是一款面向服務端應用的垃圾收集器。

在使用G1收集器時,Java堆的內存布局和其他收集器有很大的差別,它將這個Java堆分為多個大小相等的獨立區域,雖然還保留新生代和老年代的概念,但是新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續)的集合。

GC回收的觸發條件

Minor GC觸發條件:當Eden區滿時,觸發Minor GC

Full GC觸發條件:

  1. gc()方法的調用

  2. 老年代代空間不足

  3. 方法區空間不足

  4. CMS GC時出現promotion failed和concurrent mode failure

  5. 統計得到的Minor GC晉升到舊生代的平均大小大于老年代的剩余空間

  6. 堆中分配很大的對象

  7. 通過Minor GC后進入老年代的平均大小大于老年代的可用內存

  8. 由Eden區、From Space區向To Space區復制時,對象大小大于To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小于該對象大小

GC Roots

在Java語言中,可以作為GC Roots的對象包括下面幾種:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象;

  • 方法區中類靜態屬性引用的對象;

  • 方法區中常量引用的對象;

  • 本地方法棧中JNI(即一般說的Native方法)引用的對象;

總結就是,方法運行時,方法中引用的對象;類的靜態變量引用的對象;類中常量引用的對象;Native方法中引用的對象。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    單片機里的程序運行方式

    我們想要理解單片機是如何運行程序的,我們首先需要了解單片機的組成,我們這里以80C51單片機為例來理解程序在單片機中是如何運行的。 單片機的組成8051單片機的內部硬件結構包括: 中央處理器CPU
    發表于 01-16 06:57

    蜂鳥E203能夠仿真運行C語言程序嗎?

    我看那兩本書里面都是說怎么在FPGA上運行C語言程序和Benchmark程序,它提供仿真器下如何編譯運行C語言程序嗎?
    發表于 11-06 06:21

    Arm Neoverse CPU上大代碼量Java應用的性能測試

    Java 是互聯網領域廣泛使用的編程語言。Java 應用的一些特性使其性能表現與提前編譯的原生應用(例如 C 程序)大相徑庭。由于 Java 字節碼無法直接在 CPU 上執行,因此通常
    的頭像 發表于 11-05 11:25 ?752次閱讀
    Arm Neoverse CPU上大代碼量<b class='flag-5'>Java</b>應用的性能測試

    使用Nuclei Studio IDE計算程序運行時間

    在使用Nuclei Studio IDE進行程序運行時,我們想知道我們編寫的程序運行時間有多長怎么辦呢?可以選擇調用IDE里面時間記錄函數_gettimeofday(),該函數用于記錄
    發表于 10-28 08:25

    大數組程序無法運行怎么解決?

    主控是103,程序中定義一個const類型 128k只讀數組,放在flash上,程序無法運行,堆棧都初始化不了,在keil編譯下正常,在rtthread studio下編譯無法運行,求
    發表于 09-15 06:21

    Java效率提升指南:5個Java工具選型建議及Perforce JRebel和XRebel介紹

    企業級Java環境越來越復雜,真正的破局點,可能不在“人”,而在于“工具”。5個實用建議,幫你理清Java工具的選型思路。
    的頭像 發表于 09-11 13:59 ?1479次閱讀
    <b class='flag-5'>Java</b>效率提升指南:5個<b class='flag-5'>Java</b>工具選型建議及Perforce JRebel和XRebel介紹

    嵌入式系統中,FLASH 中的程序代碼必須搬到 RAM 中運行嗎?

    嵌入式系統里,FLASH 中的程序代碼并非必須搬到 RAM 中運行,這得由硬件配置、實際性能需求和應用場景共同決定。就像很多低端單片機,無論是依賴片內 Flash 還是外掛的 SPI NOR
    的頭像 發表于 08-06 10:19 ?1356次閱讀
    嵌入式系統中,FLASH 中的<b class='flag-5'>程序</b>代碼必須搬到 RAM 中<b class='flag-5'>運行</b>嗎?

    STM32 CubeIDE編譯、運行(燒錄程序)的快捷鍵是什么?

    CubeIDE編譯、運行(燒錄程序)的快捷鍵是什么?
    發表于 07-25 07:04

    EtherCAT運動控制卡應用開發教程之Java

    運動控制卡的Java開發及DLL調用
    的頭像 發表于 06-13 14:29 ?887次閱讀
    EtherCAT運動控制卡應用開發教程之<b class='flag-5'>Java</b>

    Tomcat服務器使用指南

    Expression Language(EL)等Java技術,用于支持在Java平臺上運行的動態Web應用程序。Tomcat的全名是Apache Tomcat。
    的頭像 發表于 06-09 16:26 ?1462次閱讀

    Java開發者必備的效率工具——Perforce JRebel是什么?為什么很多Java開發者在用?

    Perforce JRebel是一款Java開發效率工具,旨在幫助java開發人員更快地編寫更好的應用程序。JRebel可即時重新加載對代碼的修改,無需重啟或重新部署應用程序,就能讓開
    的頭像 發表于 04-27 13:44 ?844次閱讀
    <b class='flag-5'>Java</b>開發者必備的效率工具——Perforce JRebel是什么?為什么很多<b class='flag-5'>Java</b>開發者在用?

    如何在 樹莓派 上編寫和運行 C 語言程序

    在本教程中,我將討論C編程語言是什么,C編程的用途,以及如何在RaspberryPi上編寫和運行C程序。本文的目的是為您介紹在RaspberryPi上進行C編程的基礎知識。如果您想深入了解C編程
    的頭像 發表于 03-25 09:28 ?1155次閱讀
    如何在 樹莓派 上編寫和<b class='flag-5'>運行</b> C 語言<b class='flag-5'>程序</b>?

    零基礎入門:如何在樹莓派上編寫和運行Python程序

    在這篇文章中,我將為你簡要介紹Python程序是什么、Python程序可以用來做什么,以及如何在RaspberryPi上編寫和運行一個簡單的Python程序。什么是Python
    的頭像 發表于 03-25 09:27 ?2032次閱讀
    零基礎入門:如何在樹莓派上編寫和<b class='flag-5'>運行</b>Python<b class='flag-5'>程序</b>?

    我只會Java,憑什么不能玩轉樹莓派?GPIO操控竟比C++更優雅~

    ,而JBang更將開發門檻壓到不可思議的"單文件即運行",方便易用程度堪比Python腳本。從2012年與初代樹莓派同步誕生,到如今擁抱Java21甚至劍指JEP454黑科技。當Ja
    的頭像 發表于 03-25 09:21 ?1127次閱讀
    我只會<b class='flag-5'>Java</b>,憑什么不能玩轉樹莓派?GPIO操控竟比C++更優雅~

    用stsw-link004這個軟件配合仿真器寫程序后,直接運行程序程序運行不正常是什么原因?

    用stsw-link004這個軟件配合仿真器寫程序后,直接運行程序程序運行不正常,必須對電路板進行完全重新上電,程序才能正常
    發表于 03-07 07:00