大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 常見問題 小白如何學習Java到架構師

小白如何學習Java到架構師

更新時間:2019-09-04 13:57:57 來源:動力節點 瀏覽2918次

  一、Java運行原理

  1、高級語言運行過程

  在程序真正運行在CPU上之前,必須要讓OS的kernel理解我們在編輯器或者IDE里根據每種語言的語法規則敲入的源代碼,kernel才能做出相關的調度,所以需要先將源代碼轉化成可執行的二進制文件,這個過程通常由編譯器完成。有些編譯器直接將源代碼編譯成機器碼,載入內存后CPU可以直接運行。而機器碼的格式與跟具體的CPU架構相關連,例如ARMCPU無法理解IntelCPU機器碼。因此,同樣的源代碼需要根據不同的硬件進行特定的編譯。高級語言轉換到低級語言的橋梁就是編譯器。程序員寫好源代碼,編譯器將源碼編譯成可執行的機碼,然后CPU讀取機器碼,執行程序。

  2、Java語言的執行過程

image.png

  寬泛地講,Java源代碼(.java)經過java編譯器(javac.exe)編譯之后,并沒有直接轉化為機器碼,而是轉化成一種中間格式——字節碼(.class),字節碼再經過Java虛擬機解釋,轉化成機器碼,然后經由操作系統到達CPU運行。整個執行過程如下圖所示:

  image.png

  Java的跨平臺是基于JVM虛擬機這一中間物來實現的,Java源程序經過編譯器編譯后生成虛擬機能夠理解的字節碼(ByteCode——class文件的內容),虛擬機將每一條要執行的字節碼送給解釋器,解釋器將其翻譯成特定系統上的機器碼,然后在特定的機器上運行。每一種平臺的解釋器是不同的,但是實現的虛擬機是相同的。

image.png

  3、JVM——JavaVirtualMachine

  JVM是一個虛構出來的計算機,通過在實際的計算機上仿真模擬各種計算機功能來實現的。JVM有自己完善的硬件架構,如處理器、堆棧、寄存器等,還具有相應的指令系統。JVM的主要工作是解釋自己的指令集(即字節碼)并映射到本地的CPU的指令集或OS的系統調用。

  三、JVM的體系結構

  ClassLoader:類裝載器,從入口處開始按需加載.class文件,填充這些數據到運行時數據區

  ExecutionEngine:執行引擎,JVM的CPU,不斷地取指令,JIT編譯翻譯執行字節碼,或者執行本地方法

  RuntimeDataAreas:運行時數據區,核心區,運行的時候操作所分配的內存區,包括方法區、堆、java棧、PC寄存器、本地方法棧

image.png

  1、類加載器

  類加載器加載其實就是根據編譯后的Class文件,將Java字節碼載入JVM內存,并完成對運行數據處于的初始化工作,供執行引擎執行。

  類加載過程:

  裝載——鏈接(驗證,準備,解析)——初始化

image.png

  1.Loading:,找到二進制字節碼(Class文件)并加載至JVM內存中,標識一個被加載的類:類名+類所在的包名+ClassLoaderinstanceID

  2.Linking:

  Verifying:驗證元數據,文件格式,字節碼等,確保class文件包含的字節碼信息符合JVM的規范,以免危及JVM安全;

  Preparing:準備分配給類所需要內存的數據結構,指示在類中定義的字段、方法和接口;

  Resolving:對類中的所有屬性、方法進行驗證,以確保其需要調用的屬性、方法存在,以及具備應的權限;符號引用的轉換等

  3.Initialing:初始化執行類中的靜態初始化代碼、構造器代碼以及靜態屬性

  類裝載器類型:

  啟動類裝載器:JVM實現的一部分;

  用戶自定義類裝載器:是Java程序的一部分,必須是ClassLoader類的子類。

  類裝載順序:

  Jvm啟動時,由Bootstrap向User-Defined方向加載類;應用進行ClassLoader時,由User-Defined向Bootstrap方向查找并加載類;

  類加載采用父類委托制,子加載器能查詢父加載器已緩存類,委托只能從下到上,反之不行。類加載器可以加載一個類,但是它不能卸載一個類。但是類加載器可以被刪除或者被創建。一個類可以被不同的類加載器加載。

image.png

  BootstrapClassLoader

  JVM的根ClassLoader,它是用C++實現的,在JVM啟動的時候創建,負責裝載$JAVA_HOME中jre/lib/rt.jar(SunJDK的實現)中所有class文件,這個jar中包含了Java規范定義的所有接口以及實現。

  ExtensionClassLoader

  裝載除了基本的JavaAPI以外的擴展類,它也負責裝載其他的安全擴展功能。

  SystemClassLoader

  負責加載應用程序類,加載啟動參數中指定的Classpath中的jar包以及目錄,在SunJDK中ClassLoader對應的類名為AppClassLoader。

  User-DefinedClassLoader

  Java開發人員繼承ClassLoader抽象類自行實現的ClassLoader,基于自定義的ClassLoader可用于加載非Classpath中的jar以及目錄。

  2、執行引擎

  類加載器將.class文件載入內存之后,執行引擎以Java字節碼指令為單元,讀取Java字節碼;而后由解釋器或者即時編譯器(JITCompiler)將字節碼轉化成平臺相關的機器碼。

image.png

  JVM實現技術:

  解釋器:第一代JVM,一條一條地讀取,解釋并且執行字節碼指令。因為它一條一條地解釋和執行指令,所以它可以很快地解釋字節碼,但是執行起來會比較慢。這是解釋執行的語言的一個缺點。字節碼這種“語言”基本來說是解釋執行的。

  image.png

  即時編譯器(just-in-timecompiler):第二代JVM,狹義來說是當某段代碼即將第一次被執行時進行編譯,將class類文件解釋成二進制文件后的結果緩存下來,當第二次執行時直接從緩存中取,因此JIT依賴更多內存緩存解釋的結果。JIT編譯是動態編譯的一種特例。JIT編譯一詞后來被泛化,時常與動態編譯等價;但要注意寬泛與狹義的JIT編譯所指的區別。

  image.png

  自適應編譯器(adaptivecompiler):柔和第一代和第二代JVM,也是動態編譯的一種,但它通常執行的時機比JIT編譯遲,先讓程序“以某種形式”先運行起來,收集一些信息之后再做動態編譯,也就是說在所有執行過的代碼里只尋找一部分來編譯;而”收集信息”決定了編譯哪部分代碼,換個角度說“收集信息”就是在程序運行過程中監控代碼執行的頻率,自動緩存利用率高的代碼,這樣的編譯可以更加優化。這個”某種形式”可以稱為“baselineexecution“,可以由解釋器或簡單的JIT編譯器承擔。

  image.png

  HotSpot是一個JVM的實現,得名于它得混合模式執行引擎(包括解釋器和自適應編譯器),這個JVM最初由Longview/Animorphic實現,隨著公司被Sun/JavaSoft收購而成為Sun的JVM,并于JDK1.3.0開始成為Sun的JavaSE的主要JVM。在Sun被Oracle收購后,現在HotSpotVM是Oracle的JavaSE的主要JVM。HotSpot是較新的JVM,用來代替JIT(JustinTime),Java原先是把源代碼編譯為字節碼在虛擬機執行,這樣執行速度較慢;而HotSpot將最需要編譯的“熱點”代碼編譯為本地(原生native)代碼,如果已經被編譯成本地代碼的字節碼不再被頻繁調用了,那么HotspotVM會把編譯過的本地代碼從cache里移除,并且重新按照解釋的方式來執行它,這樣顯著提高了性能。HotSpotVM參數可以分為規則參數(standardoptions)和非規則參數(non-standardoptions)。HotspotVM分為ServerVM和ClientVM兩種,這兩種VM使用不同的JIT編譯器。

  3、運行時數據區

  當運行一個JVMInstance時,系統將分配給它一塊內存區域(大小可設置),這一內存區域由JVM自行管理。從這一塊內存中分出一塊用來存儲一些運行數據,例如創建的對象,傳遞給方法的參數,局部變量,返回值等等。這一塊內存就稱為運行數據區域。運行數據區域可以劃分為6大塊:Java棧、程序計數寄存器(PC寄存器)、本地方法棧(NativeMethodStack)、Java堆、方法區域(包括運行常量池——RuntimeConstantPool)。其中每個線程私有程序計數器,JVM棧,本地方法棧,方法區和堆則由JVM實例中的所有線程共享,在同一個實例中可以啟用多個線程。

  image.png

  程序計數器

  每個線程私有,線程啟動時創建,用來存放當前正在被執行的字節碼指令(JVM指令)的地址,如該方法為native的,則PC寄存器中不存儲任何信息。

  JVM棧

  每個線程私有,線程啟動時創建。存放著一系列的棧幀(StackFrame),JVM只能進行壓入(push)和彈出(pop)棧幀這兩種操作。每當調用一個方法時,JVM就往棧里壓入一個棧幀,方法結束返回時彈出棧幀。如果方法執行時出現異常,可用printStackTrace等方法來查看棧的情況。棧的示意圖如下:

  image.png

  每個棧幀包含三個部分:本地變量數組,操作數棧,方法所屬類的常量池引用

  LocalVariableArray:從0開始按順序存放方法所屬對象的引用、傳遞給方法的參數、局部變量。

  OperandStack:存放方法執行時的一些中間變量,JVM在執行方法時壓入或者彈出這些變量。其實,操作數棧是方法真正工作的地方,執行方法時,局部變量數組與操作數棧根據方法定義進行數據交換。

  ReferencetoConstantPool:當JVM執行到需要常量池的數據時,就是通過這個引用來訪問常量池的。棧幀中的數據還要負責處理方法的返回和異常。如果通過return返回,則將該方法的棧幀從Java棧中彈出。如果方法有返回值,則將返回值壓入到調用該方法的方法的操作數棧中。另外,數據區中還保存中該方法可能的異常表的引用。

  本地方法棧

  當程序通過JNI(JavaNativeInterface)調用本地方法(如C或者C++代碼)時,就根據本地方法的語言類型建立相應的棧,此區域用于存儲每個native方法調用的狀態。

  堆(Heap)

  堆中存放的是程序創建的對象實例以及數組值的區域,可以認為Java中所有通過new創建的對象的內存都在此分配。當堆中的空間無法滿足新建對象所需的內存開銷,會有溢出現象而導致程序崩潰,為了避免溢出,當對象執行結束時,其占據的內存空間需要等待GC(GarbageCollection)進行回收,因此這個區域對JVM的性能影響很大。

  注意:堆是JVM中所有線程共享的,因此在其上進行對象內存的分配均需要進行加鎖,導致了new對象的開銷是比較大的

  SunHotspotJVM為了提升對象內存分配的效率,對于所創建的線程都會分配一塊獨立的空間TLAB(ThreadLocalAllocationBuffer),其大小由JVM根據運行的情況計算而得,在TLAB上分配對象時不需要加鎖,因此JVM在給線程的對象分配內存時會盡量的在TLAB上分配,在這種情況下JVM中分配對象內存的性能和C基本是一樣高效的,但如果對象過大的話則仍然是直接使用堆空間分配。

  TLAB僅作用于新生代的EdenSpace,因此在編寫Java程序時,通常多個小的對象比大的對象分配起來更加高效。

  方法區域

  每個線程共享的,啟動一個JVM實例時被創建,它用于存運行放常量池、所加載的類的信息(域、方法、靜態變量、final類型的常量)。開發人員在程序中通過Class對象中的getName、isInterface等方法獲取的數據都來源于方法區域,在一定的條件下它也會被GC,當方法區域需要使用的內存超過其允許的大小時,會拋出OutOfMemory的錯誤信息。不同的JVM實現方式在實現方法區域的時候會有所區別。Oracle的HotSpot稱之為永久區域(PermanentArea)或者永久代(PermanentGeneration)。

  運行常量池

  其空間從方法區域中分配,用來存放類、方法、接口的常量和域的引用信息,當一個方法或者域被引用的時候,JVM就通過運行常量池中的引用信息來查找方法和域在內存中的的實際地址。

  四、JVM垃圾回收

  GarbageCollection的基本原理:

  將內存中不再被使用的對象進行回收,GC中用于回收的方法稱為收集器,由于GC需要消耗一些資源和時間,Java在對對象的生命周期特征進行分析后,按照新生代、舊生代的方式來對對象進行收集,以盡可能的縮短GC對應用造成的暫停。

  垃圾回收算法

  1、按照基本回收策略分為以下4種:

  ReferenceCounting:引用計數,比較古老的回收算法;原理是此對象有一個引用,即增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,引用收集計數為0的對象。此算法最致命的是無法處理循環引用的問題。

  Mark-Sweep:標記-清除,此算法執行分兩階段;第一階段從引用根節點開始標記所有被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。此算法需要暫停整個應用,同時,會產生內存碎片。

  image.png

  Copying:復制,把內存空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象復制到另外一個區域中。每次只處理正在使用中的對象,因此復制成本比較小,同時復制過去以后還能進行相應的內存整理,不會出現“碎片”問題;但是此算法的缺點就是需要兩倍內存空間。

  image.png

  Mark-Compact:標記-整理,結合了Mark-Sweep和Copying兩個算法的優點;也分兩階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,把清除未標記對象并且把存活對象“壓縮”到堆的其中一塊,按順序排放。避免了Mark-Sweep算法的碎片問題,同時也避免了Copying算法的空間問題。

  image.png

  2、按分區對待的方式分為以下2種

  IncrementalCollecting:增量收集,實時垃圾回收算法,即:在應用進行的同時進行垃圾回收。JDK5.0中的收集器沒有使用這種算法的。

  GenerationalCollecting:分代收集,基于對對象生命周期分析后得出的垃圾回收算法。把對象分為年青代、年老代、持久代,對不同生命周期的對象使用不同的算法(上述方式中的一個)進行回收。現在的垃圾回收器(從J2SE1.2開始)都是使用此算法的。

  3、按系統線程分為以下3種

  串行收集:串行收集使用單線程處理所有垃圾回收工作,因為無需多線程交互,實現容易,而且效率比較高。但是,其局限性是無法使用多處理器的優勢,所以此收集適合單處理器機器。當然,此收集器也可以用在小數據量(100M左右)情況下的多處理器機器上。

  并行收集:并行收集使用多線程處理垃圾回收工作,因而速度快,效率高。而且理論上CPU數目越多,越能體現出并行收集器的優勢。

  并發收集:相對于串行收集和并行收集而言,前面兩個在進行垃圾回收工作時,需要暫停整個運行環境,而只有垃圾回收程序在運行,因此,系統在垃圾回收時會有明顯的暫停,而且暫停時間會因為堆越大而越長。

  處理碎片

  由于不同Java對象存活時間是不一定的,因此,在程序運行一段時間以后,如果不進行內存整理,就會出現零散的內存碎片。碎片最直接的問題就是會導致無法分配大塊的內存空間,以及程序運行效率降低。所以,在上面提到的基本垃圾回收算法中,“復制”方式和“標記-整理”方式,都可以解決碎片的問題。

  對象創建和對象回收

  垃圾回收線程是回收內存的,而程序運行線程則是消耗(或分配)內存的,一個回收內存,一個分配內存,從這點看,兩者是矛盾的。因此,在現有的垃圾回收方式中,要進行垃圾回收前,一般都需要暫停整個應用(即:暫停內存的分配),然后進行垃圾回收,回收完成后再繼續應用。這種實現方式是最直接,而且最有效的解決二者矛盾的方式。

  但是這種方式有一個很明顯的弊端,就是當堆空間持續增大時,垃圾回收的時間也將會相應的持續增大,對應應用暫停的時間也會相應的增大。一些對相應時間要求很高的應用,比如最大暫停時間要求是幾百毫秒,那么當堆空間大于幾個G時,就很有可能超過這個限制,在這種情況下,垃圾回收將會成為系統運行的一個瓶頸。為解決這種矛盾,有了并發垃圾回收算法,使用這種算法,垃圾回收線程與程序運行線程同時運行。在這種方式下,解決了暫停的問題,但是因為需要在新生成對象的同時又要回收對象,算法復雜性會大大增加,系統的處理能力也會相應降低,同時碎片問題將會比較難解決。

  五、JRE(JavaRuntimeEnvironment)和JDK(JavaDevelopmentKit)

  JRE是指運行Java程序所必須的環境集合,包含JVM標準實現及Java核心類庫。JDK是Java語言的軟件開發工具包,針對Java開發員的產品,是整個Java的核心,包括了Java運行環境JRE、Java工具和Java基礎類庫。如果運行Java程序,只需安裝JRE就可以了。如果編寫Java程序,需要安裝JDK。OpenJDK則是包含了開發與運行的開源實現。最主流的JDK是Sun公司發布的JDK,除了Sun之外,還有很多公司和組織都開發了屬于自己的JDK,例如IBM,阿里等。

  根據應用領域的不同,JDK可分為三種版本:

  SE(StandardEdition)標準版,通常用的一個版本,從JDK5.0開始,改名為JavaSE

  EE(EnterpriseEdition)企業版,使用這種JDK開發J2EE應用程序,從JDK5.0開始,改名為JavaEE

  ME(MicroEdition)微型版,主要用于移動設備、嵌入式設備上的Java應用程序,從JDK5.0開始,改名為JavaME

  (轉)Java詳解JVM工作原理和流程

  作為一名Java使用者,掌握JVM的體系結構也是必須的。

  說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(JavaAPI)。它們的關系如下圖所示:

  image.png

  運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然后將之編譯成字節碼(.class文件),再然后字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

  Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫并編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

  image.png

  在Java平臺的結構中,可以看出,Java虛擬機(JVM)處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統,其中依賴于平臺的部分稱為適配器;JVM通過移植接口在具體的平臺和操作系統上實現;在JVM的上方是Java的基本類庫和擴展類庫以及它們的API,利用JavaAPI編寫的應用程序(application)和小程序(Javaapplet)可以在任何Java平臺上運行而無需考慮底層平臺,就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java的平臺無關性。

  JVM在它的生存周期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

  1、Java虛擬機的體系結構

  ·每個JVM都有兩種機制:

  ①類裝載子系統:裝載具有適合名稱的類或接口

  ②執行引擎:負責執行包含在已裝載的類或接口中的指令

  ·每個JVM都包含:

  方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

  image.png

  對于JVM的學習,在我看來這么幾個部分最重要:

  Java代碼編譯和執行的整個過程

  JVM內存管理及垃圾回收機制

  下面分別對這幾部分進行說明:

  2、Java代碼編譯和執行的整個過程

  也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然后將之編譯成字節碼(.class文件),再然后字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

  (1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。流程圖如下所示:

 image.png

  (2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

  image.png

  Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

  ·Java源碼編譯機制

  ·類加載機制

  ·類執行機制

  (1)Java源碼編譯機制

  Java源碼編譯由以下三個過程組成:

  ①分析和輸入到符號表

  ②注解處理

  ③語義分析和生成class文件

  流程圖如下所示:

 image.png

  最后生成的class文件由以下部分組成:

  ①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

  ②元數據:對應于Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

  ③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

  (2)類加載機制

  JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關系和加載順序可以由下圖來描述:  image.png

  ①BootstrapClassLoader

  負責加載$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++實現,不是ClassLoader子類

  ②ExtensionClassLoader

  負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

  ③AppClassLoader

  負責記載classpath中指定的jar包及目錄中class

  ④CustomClassLoader

  屬于應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規范自行實現ClassLoader

  加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從CustomClassLoader到BootStrapClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

  (3)類執行機制

  JVM是基于堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對于一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

  JVM執行class字節碼,線程創建后,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用于存放方法中的局部變量和參數,操作數棧中用于存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

 image.png

  3、JVM內存管理及垃圾回收機制

  JVM內存結構分為:方法區(method),棧內存(stack),堆內存(heap),本地方法棧(java中的jni調用),結構圖如下所示:

 image.png

  (1)堆內存(heap)

  所有通過new創建的對象的內存都在堆中分配,其大小可以通過-Xmx和-Xms來控制。

  操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結點,然后將該結點從空閑結點鏈表中刪除,并將該結點的空間分配給程序,另外,對于大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣代碼中的delete語句才能正確的釋放本內存空間。但由于找到的堆結點的大小不一定正好等于申請的大小,系統會自動的將多余的那部分重新放入空閑鏈表中。這時由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,它不是在堆,也不是在棧,而是直接在進程的地址空間中保留一塊內存,雖然這種方法用起來最不方便,但是速度快,也是最靈活的。堆內存是向高地址擴展的數據結構,是不連續的內存區域。由于系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。

  (2)棧內存(stack)

  在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是固定的(是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。只要棧的剩余空間大于所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。由系統自動分配,速度較快。但程序員是無法控制的。

  堆內存與棧內存需要說明:

  基礎數據類型直接在棧空間分配,方法的形式參數,直接在棧空間分配,當方法調用完成后從棧空間回收。引用數據類型,需要用new來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量。方法的引用參數,在棧空間分配一個地址空間,并指向堆空間的對象區,當方法調用完成后從棧空間回收。局部變量new出來時,在棧空間和堆空間中分配空間,當局部變量生命周期結束后,棧空間立刻被回收,堆空間區域等待GC回收。方法調用時傳入的literal參數,先在棧空間分配,在方法調用完成后從棧空間收回。字符串常量、static在DATA區域分配,this在堆空間分配。數組既在棧空間分配數組名稱,又在堆空間分配數組實際的大小。

  如:

 image.png

  (3)本地方法棧(java中的jni調用)

  用于支持native方法的執行,存儲了每個native方法調用的狀態。對于本地方法接口,實現JVM并不要求一定要有它的支持,甚至可以完全沒有。Sun公司實現Java本地接口(JNI)是出于可移植性的考慮,當然我們也可以設計出其它的本地接口來代替Sun公司的JNI。但是這些設計與實現是比較復雜的事情,需要確保垃圾回收器不會將那些正在被本地方法調用的對象釋放掉。

  (4)方法區(method)

  它保存方法代碼(編譯后的java代碼)和符號表。存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(PermanetGeneration)來存放方法區,可通過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值。

  垃圾回收機制

  堆里聚集了所有由應用程序創建的對象,JVM也有對應的指令比如new,newarray,anewarray和multianewarray,然并沒有向C++的delete,free等釋放空間的指令,Java的所有釋放都由GC來做,GC除了做回收內存之外,另外一個重要的工作就是內存的壓縮,這個在其他的語言中也有類似的實現,相比C++不僅好用,而且增加了安全性,當然她也有弊端,比如性能這個大問題。

  4、Java虛擬機的運行過程示例

  上面對虛擬機的各個部分進行了比較詳細的說明,下面通過一個具體的例子來分析它的運行過程。

  虛擬機通過調用某個指定類的方法main啟動,傳遞給main一個字符串數組參數,使指定的類被裝載,同時鏈接該類所使用的其它的類型,并且初始化它們。例如對于程序:

  image.png

  編譯后在命令行模式下鍵入:javaHelloApprunvirtualmachine

  將通過調用HelloApp的方法main來啟動java虛擬機,傳遞給main一個包含三個字符串"run"、"virtual"、"machine"的數組。現在我們略述虛擬機在執行HelloApp時可能采取的步驟。

  開始試圖執行類HelloApp的main方法,發現該類并沒有被裝載,也就是說虛擬機當前不包含該類的二進制代表,于是虛擬機使用ClassLoader試圖尋找這樣的二進制代表。如果這個進程失敗,則拋出一個異常。類被裝載后同時在main方法被調用之前,必須對類HelloApp與其它類型進行鏈接然后初始化。鏈接包含三個階段:檢驗,準備和解析。檢驗檢查被裝載的主類的符號和語義,準備則創建類或接口的靜態域以及把這些域初始化為標準的默認值,解析負責檢查主類對其它類或接口的符號引用,在這一步它是可選的。類的初始化是對類中聲明的靜態初始化函數和靜態域的初始化構造方法的執行。一個類在初始化之前它的父類必須被初始化。整個過程如下:

image.png

  以上就是動力節點Java培訓機構小編介紹的“小白如何學習Java到架構師”的內容,希望能夠幫助到大家,更多精彩內容請繼續關注動力節點Java培訓機構官網,每天會有精彩內容分享與你。

提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 嫩模尺度私拍在线视频 | 色综合网亚洲精品久久 | 日韩性大片免费 | 中文字幕精品一区二区三区视频 | 香蕉久久夜色精品国产小说 | 亚洲精品一区二区在线播放 | 国产精品人成在线播放新网站 | 九九自拍 | 成人免费毛片视频 | 狠狠地日 | 91精品国产一区二区三区左线 | 97午夜视频 | 国产色站 | 国产精品区一区二区免费 | 久久成人小视频 | 国产va | 久久精品久久精品 | 亚洲国产精品综合久久网络 | 91系列在线观看 | 国产永久免费爽视频在线 | 四虎国产一区 | 丁香狠狠| 热久久这里是精品6免费观看 | 精品一区 二区三区免费毛片 | 成人私人影院在线观看网址 | 国产成人精品日本亚洲麻豆 | 天天摸夜夜摸爽爽狠狠婷婷97 | 夜夜操天天插 | 国产成人综合网亚洲欧美在线 | 九九国产在线观看 | 尤物国产在线精品福利一区 | 波多野结衣高清在线播放 | 久久婷婷人人澡人人爱91 | 女人十八毛片一级毛片免费看 | 妞干网这里只有精品 | 久久久久成人精品一区二区 | 亚洲精品中文字幕久久久久久 | 狠狠色丁香婷婷综合欧美 | 午夜一级毛片 | 亚州视频一区 | 午夜精品久久久久久99热 |