Java虛擬機筆記-2

理論作爲指導實踐的工具

第四章 虛擬機性能監控與故障處理工具

JDK的命令行工具

數據包括:運行日誌、異常堆棧、GC日誌、線程快照(threaddump/javacore文件)、堆轉儲快照(headdump/hprof文件)等。

java.exe、javac.exe

bin目錄下的命令行工具

減少虛擬機和處理故障的工具,介紹的是基於window平臺下。

JPS:虛擬機進程狀態工具

JVM Process Status Tool,可以列出:

  • 正在運行的虛擬機進程
  • 顯示虛擬機執行主類(main()函數所在的類)
  • 進程的本地虛擬機唯一ID(LVMID)

LVMID與操作系統的進程ID(PID)是一致,使用Windows的任務管理器或UNIX的ps命令也可以查詢到LVMID

命令格式:jps [options] [hostid主機註冊名]

jstat:虛擬機統計信息監控工具(JVM Statistics Monitoring Tool)

監視虛擬機各個運行狀態信息的命令行工具,顯示本地或遠程虛擬機進程中的類加載、內存、垃圾收集、JIT編譯等數據

命令格式:jstat [option vmid [interval [s|ms] [count] ] ]

interval 代表查詢間隔,count代表查詢次數。如果省略這兩個參數說明只查詢一次。

option 代表這用戶希望查詢的虛擬機信息,主要分爲3類:類裝載、垃圾收集、運行期編譯狀況

如果是本地虛擬機進程,VMID與LVMID一致;如果是遠程虛擬機進程,VMID的格式是

jinfo:Java配置信息工具(Configuration Info for Java)

實施查看和調整虛擬機各項參數。

命令格式:jinfo [option-] pid

查看未被顯式指定的參數的系統默認值用jinfo的-flag選項查詢。

-sysprops選項將System.getProperties()的內容打印出來

jmap:Java內存映像工具(Memory Map for Java)

用於生成堆轉儲快照(heapdump或dump文件)、查詢finalize執行隊列、Java堆和永久代的詳細信息,查看每個類的實例

命令格式:jmap [option] vimd

jhat:虛擬機堆轉儲快照分析工具(JVM Heap Analysis Tool)

jhat命令與jmap搭配使用。內置了一個微型的HTTP/HTML服務器,生成dump文件的分析結果後,可以在瀏覽器中查看。

jstack:Java堆棧跟蹤工具(Stack Trace for Java)

用於生成虛擬機當前時刻的線程快照(threaddump或javacore文件)

線程快照是當前虛擬機內每一條線程正在執行的方法堆棧的集合。

生成線程快照的主要目的是定位線程出現長時間停頓的原因,如出現線程間死鎖、死循環、請求外部資源導致。

線程出現停頓的時候通過jstack查看各個線程的調用堆棧,知道沒有響應的線程在後臺做些什麼,等待什麼資源,

命令格式:jstack [option] vimd

4.2.7 HSDIS:JIT生成代碼反彙編

-XX:+PrintAssembly指令調用它來把動態生成的本地代碼還原成彙編代碼輸出

根據自己操作系統和CPU類型從Project Kenai的網站下載編譯號的插件,放到JDK_HOME/jre/bin/client和JDK_HOME/jre/bin/server

JDK的可視化工具

JConsole和VisualVM

4.3.1 JConsole:Java監視與管理控制檯

Java Monitoring and Management Console是基於JMX(Java管理擴展)的可視化監視管理工具

管理部分的功能是針對JMX MBean進行管理,由於MBean可以使用代碼、中間件服務器的管理控制檯或所有符合JMX規範的軟件進行訪問

1.啓動JConsole:在JDK/bin目錄下啓動“JConsole.exe”

2.內存監控

3.線程監控

4.3.2 VisualVm:多合一故障處理工具

All-in-One Java Troubleshooting Tool,功能:

  • 顯示虛擬機進程以及進程配置、環境信息(jps、jinfo)
  • 監視應用程序的CPU、GC、堆、方法區以及線程的信息(jstat、jstack)
  • dump以及分析堆轉儲快照(jmap、jhat)
  • 方法級的程序運行性能分析,找出被調用最多、運行時間最長的方法
  • 離線程序快照:收集程序的運行時配置、線程dump、內存dump等信息建立快照,將快照發送給開發者進行Bug反饋

2.生成、瀏覽堆轉儲快照

在VisualVM生成dump文件有兩種方式,執行下列操作:

  • 在“應用程序”窗口右鍵單擊程序節點,然後選擇“堆Dump”
  • 在“應用程序”窗口雙擊應用程序節點以打開應用程序標籤,然後在“監視”標籤中單擊“堆Dump

3.分析程序性能

4.BTrace動態日誌跟蹤

 

除了類加載時間之外,編譯時間和垃圾手機時間也十分耗時

編譯時間指虛擬機的JIT編譯器編譯熱點代碼(Hot Spot Code)的耗時

編譯後->Class文件(字節碼)->執行字節碼命令,比執行C/C++的二進制代碼慢

熱代碼交給JIT編譯器即時編譯爲本地代碼

 

虛擬機執行子系統

類文件結構

程序編譯成二進制本地機器碼(Native Code)

不同平臺的虛擬機和多有平臺統一使用的程序存儲格式——字節碼(ByteCode)

Class文件

一組以8位字節爲基礎單位的二進制流,當遇到需要佔用8位字節以上空間的數據項時,按照高位在前的方式分割成若干個8位字節進行存儲。無分隔符。

其中只有兩種數據類型:無符號數和表

無符號數屬於基本的數據類型,以u1、u2、u4、u8代表1個字節·····用來描述數字、索引引用、數量值或按照UTF-8編碼構成字符串值

表一以“_info”結尾,如下:

魔數與Class文件的版本

每個Class文件的頭4個字節,存儲版本號稱爲魔數(Magic Number),作用:確定文件是否爲一個能被虛擬機接受的Class文件。

如:0xCAFEBABE這個魔數值在Java中稱爲“Oak”語言時就存在

第7和8個字節是主版本號(Major Version)

 

常量池

  • 可理解爲Class文件之中的資源倉庫
  • 由於常量池中常量的數量不固定,所以常量池入口需要放置一項u2類型的數據,代表常量池容量計數值(constant_pool_count)從1開始。
  • 第0項常量可以用來表達:“不引用任何一個常量池項目”
  • 除了常量池的容量計數值從1開始,其他集合類型,包括接口索引集合、字段表集合、方法表集合等的容量計數與一般習慣相同,從0開始。

常量池主要存放兩大類常量:字面量和符號引用

字面量接近於Java語言的常量,如文本字符串、聲明爲final的常量值等

符號引用:

  • 類和接口的全限定名(Fully Qualified Name)
  • 字段的名稱和描述符(Descriptor)
  • 方法的名稱和描述符

Java代碼進行Javac編譯時,在虛擬機加載Class文件時進行動態連接。即Class文件中不會保存各種方法、字段的最終內存佈局信息。在運行期間進行轉換的得到內存入口地址。

 

14種常量類型

虛擬機運行時,需要從常量池獲得對應的符號引用,在類創建時或運行時解析、翻譯到具體的內存地址

 

專門用於分析Class文件字節碼的工具:javap -verbose TestClass

字段表(field_info)、方法表(method_info)、屬性表(attribute_info)引用。

 

訪問標誌

常量池結束之後,緊接着兩個字節代表訪問標誌(access_flags),一共16個標誌位可以使用。沒使用的標誌位爲0.

用來識別類或接口層次的訪問信息,包括這個class是類還是接口;是否定義爲public類型;是否定義爲abstract類型等等。

類索引、父類索引與接口索引集合

類索引(this_class)和父類索引(super_class)都是一個u2(2個字節)類型的數據

接口索引集合(interfaces)是一組u2類型的數據集合

類索引:確定這個類的全限定名

父類索引:確定這個類的父類的全限定名,父類索引只有1個。接口計數器表示索引表的容量

接口索引集合:描述這個類實現哪些接口

字段表集合

字段表(field_info):描述接口或類中聲明的變量。

字段(field)包括類級變量以及實例級變量,但不包括在方法內部聲明的局部變量。

 

Java字段包含字段的作用域(public、private、protected修飾符)、實例變量、類變量(static修飾符)、可變性(final)、併發可見性(volatile修飾符,是否強制從主存讀寫)、可否被序列化(transient修飾符)、字段數據類型(基本類型、對象、數組)、字段名稱

跟隨訪問標誌(access_flags)的是兩項索引值:name_index(字段的簡單名稱)和descriptor_index(字段和方法的描述符)。都是對常量池的引用。

全限定名:把類全名中的“.”替換成“/”,用“;”表示全限定名結束

簡單名稱:沒有類型和參數修飾的方法或字段名

描述符:描述字段的數據類型、方法的參數列表(包括數量、類型及順序)、返回值

基本數據類型:byte、char、double、float、int、short、long、boolean

代表無返回值的void類型用一個大寫字符表示。

數組用“[”表示,如int[]記錄爲“[I”-

描述方法:參數列表放在“()”之內,如方法void inc()的描述符爲“()V”,方法java.lang.String.toString()的描述符爲“()Ljava/lang/String”

方法表集合

包括訪問標誌(access_flags)、名稱索引(name_index)、描述符索引(descriptor_index)、屬性表集合(attributes)

共享變量被volatile關鍵字修飾,保證修改的值會立即更新到主存,當其他線程讀取時,會去主存中讀取新值。確保可見性和有序性

CPU執行速度快,但是內存讀取數據和寫入數據很慢,所以將數據從主存中複製一份到CPU的高速緩存中,運算結束後將高速緩存的數據更新到主存中。

每個線程都有自己的高速緩存,出現緩存不一致問題,解決方法MESI協議保證了每個緩存中使用的共享變量的副本是一致的。它核心的思想是:當CPU寫數據時,如果發現操作的變量是共享變量,即在其他CPU中也存在該變量的副本,會發出信號通知其他CPU將該變量的緩存行置爲無效狀態,因此當其他CPU需要讀取這個變量時,發現自己緩存中緩存該變量的緩存行是無效的,那麼它就會從內存重新讀取。

重載:與原方法名相同的簡單名稱,還必須擁有一個與原方法不同的特徵簽名。

特徵簽名:一個方法中各個參數在常量池中的字段符號引用的集合。(返回值不包含在特徵簽名)

 

JVM會進行指令重排序

synchronized(同步)和Lock

 

happens-before (先行發生)原則

  • 程序次序規則:一個線程內,按照代碼順序,書寫在前面的操作0000000先行發生於書寫在後面的操作
  • 鎖定規則:一個unLock操作先行發生於後面對同一個鎖額lock操作
  • volatile變量規則:對一個變量的寫操作先行發生於後面對這個變量的讀操作
  • 傳遞規則:如果操作A先行發生於操作B,而操作B又先行發生於操作C,則可以得出操作A先行發生於操作C
  • 線程啓動規則:Thread對象的start()方法先行發生於此線程的每個一個動作
  • 線程中斷規則:對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生
  • 線程終結規則:線程中所有的操作都先行發生於線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到線程已經終止執行
  • 對象終結規則:一個對象的初始化完成先行發生於他的finalize()方法的開始

屬性表集合

1.Code屬性

方法體中的代碼經過Javac編譯器處理後,變成字節碼指令儲存在Code屬性內。

Class文件中最重要的一個屬性,Java程序的信息分成代碼(Code)和元數據(Metadata,包括類、字段、方法定義及信息)

任何實例方法裏面,都可以通過this關鍵字訪問此方法所屬的對象。

字節碼指令之後的是這個方法的顯式異常處理表集合。實現Java異常及finally處理機制

2.Exceptions屬性

與異常表的區別

作用:列舉方法中可能拋出的受查異常(Checked Exception),也就是方法描述時在throws關鍵字後面列舉的異常。

3.LineNumberTable屬性

描述Java源碼行號與字節碼行號(字節碼的偏移量)之間的對應關係。默認會生成到Class文件中。

通過-g:none或-g:lines取消這項信息,但當拋出異常之後,就不會顯示出錯的行號。

4.LocalVariableTable屬性

作用:描述棧幀中局部變量表中的變量與Java源碼中定義的變量之間的關係,默認會生成到Class文件中。

通過-g:none或-g:vars取消這項信息,但當其他人引用這個方法,所有參數名稱都會丟失。

5.SourceFile屬性

記錄生成這個Class文件的源碼文件名稱。

使用-g:none或-g:source選項關閉或要求生成這項信息。當拋出異常時,堆棧中將不會顯示出錯代碼所屬的文件名。

6.ConstantValue屬性

通知虛擬機自動爲靜態變量(被static關鍵字修飾)賦值。

 

非static類型變量(實例變量)的賦值在實例構造器<init>方法中進行。類變量(靜態變量)有兩種方式:在類構造器<clinit>方法中或者使用ConstantValue屬性。具體如下:

常量:final static修飾的變量,類型爲基本類型或String,生成ConstantValue屬性進行初始化。

如果沒有final修飾或並非基本類型及String就可在類構造器<clinit>方法初始化。

 

7.InnerClasses屬性:記錄內部類和宿主類之間的關聯。

8.Deprecated和Synthetic屬性

標誌類型的布爾屬性。只存在有和沒有,沒有屬性值概念

Deprecated:表示某個類、字段或方法,已被程序作者定爲不推薦使用,@deprecated修飾

Synthetic:代表此方法或字段、方法並不是由Java源碼直接生產,而是由編譯器自行添加。

9.StackMapTable屬性

是一個複雜的變長屬性,位於Code屬性的屬性表。在虛擬機類加載的字節碼驗證階段被新類型檢查驗證器(Type Checker)使用。代替類型推導驗證器。

10.Signature屬性

記錄泛型類型,Java採用擦除法實現僞泛型。

11.BootstrapMethods屬性

是一個複雜的變長屬性,位於類文件的屬性表中。用於保存invokedynamic指令引用的引導方法限定符。

 

字節碼指令簡介

操作碼+操作數

操作碼:一個字節長度的(0~255),代表這某種特定操作含義的數字

操作數:跟隨在操作碼後的零至多個代表此操作所需參數而構成

JVM採用面向操作數棧架構,而不是寄存器(區別見第八章)。大多數的指令都不包含操作數,只有操作碼。

Class文件格式放棄操作數長度對齊

字節碼與數據類型

指令包含:所對應的數據類型信息。如iload指令用於從局部變量表中加載int型的數據導操作數棧中;fload類型的數據值加載float類型的數據。

int-i;short-s;byte-b;char-c;float-f;double-d;reference-a

Not Orthogonal:指令集將設計成非完全獨立的。

編譯器會在編譯期或運行期將byte和short類型的數據帶符號擴展(Sign-Extend)爲相應的int類型數據。boolean和char類型零位擴展(Zero-Extend)爲相應的int類型數據

加載和存儲指令

用於將數據在棧幀中的局部變量表和操作數棧之間來回傳輸

  • 將一個局部變量加載到操作棧:iload、iload<n>、lload、lload<n>、fload、dload、aload等
  • 將一個數值從操作數棧存儲到局部變量表:istore、istore_<n>、lstore、lstore_<n>等
  • 將一個常量加載到操作數棧:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_ml、iconst_<i>、lconst_<j>、fconst_<f>、dconst_<d>
  • 擴充局部變量表的訪問索引的指令:wide

運算指令

運算或算術指令用於對兩個操作數棧上的值進行某種特定運算,並把結果重新存入到操作棧頂。

加法指令:iadd、ladd、fadd、dadd

減法指令:isub、lsub、fsub、dsub

乘法指令:imul、lmul、fmul、dmul

除法指令:idiv、ldiv、fdiv、ddiv

求餘指令:irem、lrem、frem、drem

取反指令:ineg、lneg、fneg、dneg

非正規浮點數值(Denormalized Floating Point Numbers)和逐級下溢(Gradual Underflow)

浮點數運算時,所有的運算結果都必須舍入到適當的精度。最接近數舍入模式

向零舍入模式會導致數字被截斷,所有小數部分的有效字節會被丟棄掉。

 

 

 

 

 

 

突然去看紀錄片就順便記錄一下,哈哈哈

恆星的演化

星際雲(氣體或固體,H、He)

引力、收縮、旋轉、升溫=>原恆星  H->He    失敗:褐矮星、棕矮星  紅矮星:比鄰星  黃矮星:太陽  藍色大恆星:手槍星

主序星:穩定

黃矮星->紅巨星->星雲,白矮星->黑矮星

藍色大恆星->紅超巨星->黑洞、超新星爆發、中子星

 

電子簡併壓:電子滿足泡利不相容原理(不能有兩個或兩個以上的粒子處於完全相同的狀態),對抗的壓力可以對抗引力

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章