程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> java虛擬機學習筆記

java虛擬機學習筆記

編輯:關於JAVA

1.編譯順序: 編譯器 虛擬機 虛擬機 java源文件*.Java------->字節碼*.class------>類裝載器--->執行引擎

一個.class文件只能包含一個類或接口。因此.Java文件中定義了多少類,編譯時就會生成多少.class文件(內部類不算)。

2.java程序可以選擇兩種方式訪問底層系統,由程序員選擇:(1).通過java程序調用javaapi調用本地方法,訪問底層系統,與平台無關。(2).通過Java程序直接調用本地方法,訪問底層系統與平台相關。本地方法即操作系統提供的方法。

3.類裝載器:裝載java編譯器編譯好的字節碼*.class和Java api的字節碼到方法區。

Java有兩種類裝載器:(1).啟動類裝載器:系統唯一,屬於虛擬機的一部分,用特定語言編寫(與虛擬機體層語言相通)使用默認方式裝載類,主要用來裝載核心類庫

。(2).用戶自定義類裝載器:可有任意多個,用java編寫,屬於Java應用程序的一部分,能被編譯成字節碼,並被虛擬機所裝載。

一個裝載器裝載一個類及其該類所調用的一切類,使他們相互聯系,並形成一個命名空間(name space),每一個類裝載器對應一個命名空間。

即Java中名字空間的原理。

類裝載器成線形排列,自底向上,頂部為啟動類裝載器。除啟動類裝載器外,其他類裝載器都由用戶實例化,用來裝載不同的類。當要裝載一

個類時,底部的裝載器試圖將該類交給父裝載器裝載,而該父類又試圖交給他的父類裝載,一直向上,直到啟動類裝載器。若父類裝載器無法

裝載,則交給子類裝載器裝載,子類裝載能裝載的部分,將余下部分交給他的子類,直到底部。如:裝載器a,b,c,d,e,f,啟動a--->b--->c--->d--->e--->f--->啟動當有一個類fun需要被裝載時,他會一直上溯到頂部即啟動類裝載器。如果啟動類裝載器無法裝載fun則交給f裝載,f裝載能裝載的部分,將其

余部分交給e,然後一直這樣下去。

如上所述,運行過程中每個類裝載器裝載的類形成一個運行時包,同一運行時包裡的類可以互相訪問,但不能訪問包外部的類。

4.虛擬機的生命周期:每個Java程序都有自己的虛擬機實例,隨著程序的產生和消亡而產生與消亡。

5.java程序運行時的內存結構:程序空間分為方法區,堆,Java棧,本地方法棧。

(1)方法區存放裝載的類數據信息包括:基本信息:每個類的全限定名。每個類的直接超類的全限定名(可約束類型轉換)。該類是類還是接口。該類型的訪問修飾符。直接超接口的全限定名的有序列表。

每個已裝載類的詳細信息:運行時常量池:存放該類型所用的一切常量(直接常量和對其他類型,字段,方法的符號引用),它們以數組形式通過索引被訪問,是外部調用

與類聯系及類型對象化的橋梁。它是類文件(字節碼)常量池的運行時表示。(還有一種靜態常量池,在字節碼文件中)。字段信息:類中聲明的每一個字段的信息(名,類型,修飾符)。方法信息:類中聲明的每一個方法的信息(名,放回類型,參數類型,修飾符,方法的字節碼和異常表)。靜態變量到類classloader的引用:即到該類的類裝載器的引用。到類class的引用:虛擬機為每一個被裝載的類型創建一個class實例,用來代表這個被裝載的類。

(2)堆存放所有生成的對象及對象的實例變量。

(3)Java棧以幀的形似存放本地方法的調用狀態(包括方法調用的參數,局部變量,中間結果等)。每調用一個方法就將對應該方法的方法幀壓入

Java棧,成為當前方法幀。當調用結束(返回)時,就彈出該幀。編譯器將原代碼編譯成字節碼(.class)時,就已經將各種類型的方法的局部變

量,操作數棧大小確定並放在字節碼中,隨著類一並裝載入方法區。當調用方法時,通過訪問方法區中的類的信息,得到局部變量以及操作數

棧的大小。

Java棧幀(即方法幀)由局部變量區,操作數棧,幀數據區組成。

局部變量區為一個以字為單位的數組,每個數組元素對應一個局部變量的值。調用方法時,將方法的局部變量組成一個數組,通過索引來訪問

。若為非靜態方法,則加入一個隱含的引用參數this,該參數指向調用這個方法的對象。而靜態方法則沒有this參數。因此,對象無法調用靜態

方法。

操作數棧也是一個數組,但卻是通過棧操作來訪問。所謂操作數是那些被指令操作的數據。當需要對參數操作時如a=b+c,就將即將被操作的參

數壓棧,如將b和c壓棧,然後由操作指令將他們彈出,並執行操作,此處由iadd指令將b和c彈出並相加,然後壓入操作數棧(一系列均由iadd執

行)然後由i_storex指令將結果彈出,存到索引x指向的局部變量區數組內(此處索引x指向局部變量a)。虛擬機將操作數棧作為工作區。

幀數據區處理常量池解析,異常處理等。

(4)本地方法棧:與調用的本地方法的語言相關,如調用的是一個c語言方法則為一個c棧。本地方法可以回調java方法。若有java方法調用本地方法,虛擬機就運行這個本地方法。在虛擬機看來運行這個本地方法就是執行這個Java方法,如果本地方法拋出異常,

虛擬機就認為是這個Java方法拋出異常。

(5)執行程序時,通過對象的引用在方法區中查找裝載的類,若還沒有裝載,則查找字節碼(類名.class),並將其裝載入方法區。在執行過程中,虛擬機會將對象的符號引用(即對象名)替換為直接的指針,以提高訪問速度。

(6)因此,大體可以表述為:方法區:存儲類包括接口的各種信息,字節碼裝載到此處。java棧:存儲被調用的方法的各種信息,只有調用該方法時,才會將該方法幀壓入java棧。堆:存儲對象的信息,包括對象的實例變量,但不包括對象的方法。只有調用對象的方法時,才將方法幀壓入Java棧中。

6.Java數據類型:數值類型:浮點類型:float double整數類型:byte,short,int,long,char(int和char可以互換)。引用類型:類類型,接口類型,數組類型。

7.Java的引用類型:引用與指針。引用代表被引用的對象,它只是引用對象的代表,並不占用內存,也不能修改。如引用變量沒有引用對象,則該引用變量=null。指針存放對象的地址,它是一個變量,可以被修改,和其他變量一樣,占用內存。

8.方法區所有線程共享方法區,但為滿足線程安全,方法區中每一個類必須被設定為臨界資源,即同一時刻某一個類只能被一個線程訪問。

9.類標識:由於一個程序可以多次裝載同一個類且該類可以存在於不同的名字空間中(即可由不同的裝載器裝載),因此必須將裝載該類的裝載器的標識加

上,才能唯一標識一個類。

10.對象對象實例變量存儲在堆中,對象符號引用則在常量池,方法屬性表等可能出現的地方。通過對象的引用可以訪問對象的實例數據和創建該對象

的類的數據。對象的引用指向堆中的對象。實例結構有兩種,見書本98頁。

當調用對象的方法時,需要進行動態綁定。即,不能根據對象來確定需要調用的方法,而是根據對象的類數據來確定需要調用的方法。此時,

也需要通過對象的引用來訪問類數據。動態綁定就是在運行時才綁定,而不是在編譯時綁定。

11.數組數組也是類的對象。具有相同類型和維數的數組屬於同一個類(不管長度只看維數)。數組的長度屬於對象實例。多維數組也是一維數組。如二

維數組,即為一個一維數組,該一維數組的每個元素是一個數組的引用。數組和普通對象一樣也存儲在堆中。數組名為數組的引用,通過索引即數組標號來訪問數組內容。

12.異常在Java棧幀的幀數據區內保存有針對該方法的異常表的引用。異常表記載了該方法的字節碼(*.class)受catch子句保護的范圍(即try子句裡的

字節碼)。當某個方法拋出異常時,虛擬機在對應的異常表中尋找匹配的catch子句,並將控制權交給catch子句中的代碼。

13.java執行引擎實現平台無關性,以Java方法幀裡的操作數棧為中心,將局部變量數組當作CPU的寄存器。每操作一個數據都要壓人操作數棧,然後返回至局部

變量區。Java虛擬機規定強類型轉換,即低精度可以隱式轉換到高精度,高精度必須強制轉換到低精度。

14.線程線程即存在於進程中的某個執行體。每個線程必須遵守對象鎖定,線程等待和通知。對象鎖定使線程互斥的訪問對象資源。等待和通知則是遵守線程合理調度以達到同一個目的。Java對象通過指令集達到上鎖目的,同過繼承

object類的wait(),notify(),notifyall()方法來等待和通知。當某個線程調用某個對象的wait()方法時,該線程被阻塞,並加入到該對象的線

程阻塞隊列中,直到另一個線程調用同一對象的通知方法,才能喚醒阻塞隊列中的線程。

15.常量池常量池用來存放類型的各種信息,包括類型的各種直接常量,和對其他類型,字段,方法的符號引用。常量池分為兩種,存儲在.class字節碼中的常量池和存儲在方法區中的運行時常量池。常量池以入口形式(類似於中斷向量表)出現,每個入口都指向一個表,表中存儲常量的信息。但從常量池的入口的標志位就可以判斷對應的表

中存儲的常量類型。常量池入口以一個標志位開始,該標志位指示該常量的類型。每個入口對應一個表,該表以符號_info結尾,表中存放常量的壓縮形式。常量池除了存放直接常量外還容納如下幾種符號引用:類和接口的全限定名。字段名稱和描述符(該描述符是一個指示字段類型的字符串。字段是一個類或接口的類變量或實例變量)。方法名稱和描述符(該描述符指示方法返回類型,參數類型,數量,順序)。

運行時,虛擬機用常量池的全限定名和方法,字段的描述符來建立類與類的關系。

常量池僅僅是一個引用和描述符的集合,並不接受任何賦值操作。

所有對象的創建,方法和類變量的調用均要從常量池中獲取信息,但實例變量的調用從堆裡獲得。(猜想)

符號引用是由虛擬機解析後得到具體的地址來使用。

常量池解析就是將常量池中的符號引用替換成直接引用。

當要使用某個類的方法或字段時,首先從常量池中找到該方法或字段的符號引用,然後進行解析,找到其物理地址。

把代碼中出現的各種符號引用,類與類的聯系,進行常量池解析,叫做動態連接。

16.常量池結構常量池由很多狠多的單元組成,每一個單元都形如(入口|內容),訪問常量池單元時通過索引找到入口,然後訪問其內容。但有時單元的內容也

可能是一個常量池入口(比如類或接口的常量池單元,入口包含該類的符號引用即constant_class_info,而內容則指向一個

constant_utf8_info的常量池單元,該單元裡存放了該類的全限定名)。而直接常量如int,float等,內容處就是常量的值。

17.方法區的結構方法區存儲所有關於類型,接口的信息。方法區包含:

常量池:存儲類型的直接常量和所有的字段,方法,其他類型的符號引用(僅僅是引用,並不存放具體信息)。

字段信息:所有聲明的字段(包括字段名,類型,修飾符)。

方法信息:所有定義的方法(包括方法名,返回類型,修飾符,方法的字節碼,方法棧幀的大小,方法的異常)。

類變量信息:虛擬機在方法區中為所有類變量分配空間,以後的初始化,賦值等操作也在方法區中進行,以便為所有類實例共享。

為提高訪問速度,虛擬機在方法區中為每個非抽象類設置了一個方法表,該表是一個數組,每個元素是一個方法的直接引用。當類的對象調用

方法時,就在方法表中搜索(抽象類沒有實例,所以不用調用方法,所以沒有方法表)。

18.堆堆存放類的實例和數組(包括實例變量,指向對應方法區中類數據的引用)。

19.一個例子class test{public static void main(string args[]){string a=new string("hello");string b=new string("hello");string c="hello";string d="hello";}}則a==b返回false,c==d返回ture。因為:==比較雙方是否是同一個對象。

首先:string a=new string("hello")string b=new string("hello")a和b分別各自新建了hello的對象和引用變量,即在堆中有兩個hello,他們各自的引用是a和b。

而:string c="hello"string d="hello"先建立一個字符串類實例hello,再建立兩個字符串引用變量c和d,然後讓c和d都指向開始建立的hello實例。因此c和d指向的是同一個對象。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved