免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
借助HotSpot SA來(lái)一窺PermGen上的對(duì)象
(Disclaimer:如果需要轉(zhuǎn)載請(qǐng)先與我聯(lián)系;
作者:RednaxelaFX -> rednaxelafx.iteye.com)
接著前天的昨天的帖,今天也來(lái)介紹一個(gè)HotSpotServiceability Agent(以下簡(jiǎn)稱SA)的玩法例子。
昨天用SA把x86機(jī)器碼反匯編到匯編代碼,或許對(duì)多數(shù)Java程序員來(lái)說(shuō)并不怎么有趣。那么今天就來(lái)點(diǎn)更接近Java,但又經(jīng)常被誤解的話題——HotSpot的GC堆的permanent generation。
要用SA里最底層的API來(lái)連接上一個(gè)Java進(jìn)程并不困難,不過(guò)SA還提供了更方便的封裝:只要繼承 sun.jvm.hotspot.tools.Tool 并實(shí)現(xiàn)一個(gè) run() 方法,在該方法內(nèi)使用SA的API訪問(wèn)JVM即可。
這次我們就把一個(gè)跑在HotSpot上的Java進(jìn)程的perm gen里所有對(duì)象的信息打到標(biāo)準(zhǔn)輸出流上看看吧。
測(cè)試環(huán)境是32位Linux,x86,Sun JDK 6 update 2
(手邊可用的JDK版本很多,隨便拿了一個(gè)來(lái)用,呵呵 >_<)
代碼如下:
Java代碼 
 
import sun.jvm.hotspot.gc_implementation.parallelScavenge.PSPermGen;
import sun.jvm.hotspot.gc_implementation.parallelScavenge.ParallelScavengeHeap;
import sun.jvm.hotspot.gc_implementation.shared.MutableSpace;
import sun.jvm.hotspot.gc_interface.CollectedHeap;
import sun.jvm.hotspot.memory.Universe;
import sun.jvm.hotspot.oops.HeapPrinter;
import sun.jvm.hotspot.oops.HeapVisitor;
import sun.jvm.hotspot.oops.ObjectHeap;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
/**
* @author sajia
*
*/
public class TestPrintPSPermGen extends Tool {
public static void main(String[] args) {
TestPrintPSPermGen test = new TestPrintPSPermGen();
test.start(args);
test.stop();
}
@Override
public void run() {
VM vm = VM.getVM();
Universe universe = vm.getUniverse();
CollectedHeap heap = universe.heap();
puts("GC heap name: " + heap.kind());
if (heap instanceof ParallelScavengeHeap) {
ParallelScavengeHeap psHeap = (ParallelScavengeHeap) heap;
PSPermGen perm = psHeap.permGen();
MutableSpace permObjSpace = perm.objectSpace();
puts("Perm gen: [" + permObjSpace.bottom() + ", " + permObjSpace.end() + ")");
long permSize = 0;
for (VM.Flag f : VM.getVM().getCommandLineFlags()) {
if ("PermSize".equals(f.getName())) {
permSize = Long.parseLong(f.getValue());
break;
}
}
puts("PermSize: " + permSize);
}
puts();
ObjectHeap objHeap = vm.getObjectHeap();
HeapVisitor heapVisitor = new HeapPrinter(System.out);
objHeap.iteratePerm(heapVisitor);
}
private static void puts() {
System.out.println();
}
private static void puts(String s) {
System.out.println(s);
}
}
很簡(jiǎn)單,假定目標(biāo)Java進(jìn)程用的是Parallel Scavenge(PS)算法的GC堆,輸出GC堆的名字,當(dāng)前perm gen的起始和結(jié)束地址,VM參數(shù)中設(shè)置的PermSize(perm gen的初始大小);然后是perm gen中所有對(duì)象的信息,包括對(duì)象摘要、地址、每個(gè)成員域的名字、偏移量和值等。
對(duì)HotSpot的VM參數(shù)不熟悉的同學(xué)可以留意一下幾個(gè)參數(shù)在HotSpot源碼中的定義:
C++代碼 
 
product(ccstrlist, OnOutOfMemoryError, "",
"Run user-defined commands on first java.lang.OutOfMemoryError")
product(bool, UseParallelGC, false, "Use the Parallel Scavenge garbage collector")
product_pd(uintx, PermSize, "Initial size of permanent generation (in bytes)")
product_pd(uintx, MaxPermSize, "Maximum size of permanent generation (in bytes)")
要讓SA連接到一個(gè)正在運(yùn)行的Java進(jìn)程最重要是提供進(jìn)程ID。獲取pid的方法有很多,今天演示的是利用OnOutOfMemoryError參數(shù)指定讓HotSpot在遇到內(nèi)存不足而拋出OutOfMemoryError時(shí)執(zhí)行一段用戶指定的命令;在這個(gè)命令中可以使用%p占位符表示pid,HotSpot在執(zhí)行命令時(shí)會(huì)把真實(shí)pid填充進(jìn)去。
然后來(lái)造一個(gè)引發(fā)OOM的導(dǎo)火索:
Java代碼 
 
public class Foo {
public static void main(String[] args) {
Long[] array = new Long[256*1024*1024];
}
}
對(duì)32位HotSpot來(lái)說(shuō),main()方法里的new Long[256*1024*1024]會(huì)試圖創(chuàng)建一個(gè)大于1GB的數(shù)組對(duì)象,那么只要把-Xmx參數(shù)設(shè)到1GB或更小便足以引發(fā)OOM了。
如何知道這個(gè)數(shù)組對(duì)象會(huì)占用超過(guò)1GB的呢?Long[]是一個(gè)引用類型的數(shù)組,只要知道32位HotSpot中采用的對(duì)象布局:
-----------------------(+0) | _mark | -----------------------(+4) | _metadata | -----------------------(+8) | 數(shù)組長(zhǎng)度 length | -----------------------(+12+4*0) | 下標(biāo)為0的元素 | -----------------------(+12+4*1) | 下標(biāo)為1的元素 | ----------------------- | ... | -----------------------(+12+4*n) | 下標(biāo)為n的元素 | ----------------------- | ... | -----------------------
就知道一大半了~
跑一下Foo程序。留意到依賴SA的代碼要編譯的話需要$JAVA_HOME/lib/sa-jdi.jar在classpath上,執(zhí)行時(shí)同理。指定GC算法為Parallel Scavenge,并指定Java堆(不包括perm gen)的初始和最大值都為1GB:
Command prompt代碼 
[sajia@sajia ~]$ java -server -version
java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b05)
Java HotSpot(TM) Server VM (build 1.6.0_02-b05, mixed mode)
[sajia@sajia ~]$ javac Foo.java
[sajia@sajia ~]$ javac -classpath ".:$JAVA_HOME/lib/sa-jdi.jar" TestPrintPSPermGen.java
[sajia@sajia ~]$ java -server -XX:+UseParallelGC -XX:OnOutOfMemoryError='java -cp $JAVA_HOME/lib/sa-jdi.jar:. TestPrintPSPermGen %p > foo.txt' -Xms1g -Xmx1g Foo
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="java -cp $JAVA_HOME/lib/sa-jdi.jar:. TestPrintPSPermGen %p > foo.txt"
#   Executing /bin/sh -c "java -cp $JAVA_HOME/lib/sa-jdi.jar:. TestPrintPSPermGen 23373 > foo.txt"...
Attaching to process ID 23373, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 1.6.0_02-b05
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at Foo.main(Foo.java:5)
[sajia@sajia ~]$
得到的foo.txt就是要演示的輸出結(jié)果。把它壓縮了放在附件里,有興趣但懶得自己實(shí)驗(yàn)的同學(xué)也可以觀摩一下~
在foo.txt的開(kāi)頭可以看到:
Log代碼 
GC heap name: ParallelScavengeHeap
Perm gen: [0x70e60000, 0x71e60000)
PermSize: 16777216
這里顯示了GC堆確實(shí)是Parallel Scavenge的,其中perm gen當(dāng)前的起始地址為0x70e60000,結(jié)束地址為0x71e60000,中間連續(xù)的虛擬內(nèi)存空間都分配給perm gen使用。簡(jiǎn)單計(jì)算一下可知perm gen大小為16MB,與下面打出的PermSize參數(shù)的值完全吻合。
通過(guò)閱讀該日志文件,可以得知HotSpot在perm gen里存放的對(duì)象主要有:
- Klass系對(duì)象
- java.lang.Class對(duì)象
- 字符串常量
- 符號(hào)(Symbol/symbolOop)常量
- 常量池對(duì)象
- 方法對(duì)象
等等,以及它們所直接依賴的一些對(duì)象。具體這些都是什么留待以后有空再寫(xiě)。
接下來(lái)挑幾個(gè)例子來(lái)簡(jiǎn)單講解一下如何閱讀這個(gè)日志文件里的對(duì)象描述。
首先看一個(gè)String對(duì)象。先看看JDK里java.lang.String對(duì)象的聲明是什么樣的:
Java代碼 
package java.lang;
// imports ...
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// ...
}
}
留意到String對(duì)象有4個(gè)成員域,分別是:
名字類型引用類型還是值類型
valuechar[]引用類型
offsetint值類型
countint值類型
hashint值類型
String類自身有三個(gè)靜態(tài)變量,分別是:
名字類型引用類型還是值類型備注
serialVersionUIDlong值類型常量
serialPersistentFieldsjava.io.ObjectStreamField[]引用類型只讀變量
CASE_INSENSITIVE_ORDERjava.lang.String.CaseInsensitiveComparator引用類型只讀變量
回到我們的foo.txt日志文件來(lái)看一個(gè)String的對(duì)象實(shí)例:
Log代碼 
"main" @ 0x7100b140 (object size = 24)
- _mark:    {0} :1
- _klass:   {4} :InstanceKlass for java/lang/String @ 0x70e6c6a0
- value:    {8} :[C @ 0x7100b158
- offset:   {12} :0
- count:    {16} :4
- hash:     {20} :0
這是在HotSpot的字符串池里的一個(gè)字符串常量對(duì)象,"main"。
日志中的“"main"”是對(duì)象的摘要,String對(duì)象有特別處理顯示為它的內(nèi)容,其它多數(shù)類型的對(duì)象都是顯示類型名之類的。
在@符號(hào)之后的就是對(duì)象的起始地址,十六進(jìn)制表示。
緊接著后面是對(duì)象占用GC堆的大小。很明顯這個(gè)String對(duì)象自身占用了24字節(jié)。這里強(qiáng)調(diào)是“占用”的大小是因?yàn)閷?duì)象除了存儲(chǔ)必要的數(shù)據(jù)需要空間外,為了滿足數(shù)據(jù)對(duì)齊的要求可能會(huì)有一部分空間作為填充數(shù)據(jù)而空占著。
String在內(nèi)存中的布局是:
-----------------------(+0) | _mark | -----------------------(+4) | _metadata | -----------------------(+8) | value | -----------------------(+12)| offset | -----------------------(+16)| count | -----------------------(+20)| hash | -----------------------
32位HotSpot上要求64位/8字節(jié)對(duì)齊,String占用的24字節(jié)正好全部都是有效數(shù)據(jù),不需要填充空數(shù)據(jù)。
上面的String實(shí)例在內(nèi)存中的實(shí)際數(shù)據(jù)如下:
偏移量(字節(jié))數(shù)值(二進(jìn)制表示)數(shù)值(十六進(jìn)制表示)寬度(位/字節(jié))
+0000000000000000000000000000000010000000132位/4字節(jié)
+40111000011100110110001101010000070e6c6a032位/4字節(jié)
+8011100010000000010110001010110007100b15832位/4字節(jié)
+12000000000000000000000000000000000000000032位/4字節(jié)
+16000000000000000000000000000001000000000432位/4字節(jié)
+20000000000000000000000000000000000000000032位/4字節(jié)
OK,那我們來(lái)每個(gè)成員域都過(guò)一遍,看看有何玄機(jī)。
第一個(gè)是_mark。在HotSpot的C++代碼里它的類型是markOop,在SA里以sun.jvm.hotspot.oops.Mark來(lái)表現(xiàn)。
它屬于對(duì)象頭(object header)的一部分,是個(gè)多用途標(biāo)記,可用于記錄GC的標(biāo)記(mark)狀態(tài)、鎖狀態(tài)、偏向鎖(bias-locking)狀態(tài)、身份哈希值(identity hash)緩存等等。它的可能組合包括:
比特域(名字或常量值:位數(shù))標(biāo)識(shí)(tag)狀態(tài)
身份哈希值:25, 年齡:4, 0:101未鎖
鎖記錄地址:3000被輕量級(jí)鎖住
monitor對(duì)象地址:3010被重量級(jí)鎖住
轉(zhuǎn)向地址:3011被GC標(biāo)記
線程ID:23, 紀(jì)元:2, 年齡:4, 1:101被偏向鎖住/可被偏向鎖
例子中的"main"字符串的_mark值為1,也就是說(shuō)它:
- 沒(méi)有被鎖住;
- 現(xiàn)在未被GC標(biāo)記;
- 年齡為0(尚未經(jīng)歷過(guò)GC);
- 身份哈希值尚未被計(jì)算。
HotSpot的GC堆中許多創(chuàng)建沒(méi)多久的對(duì)象的_mark值都會(huì)是1,屬于正?,F(xiàn)象。
接下來(lái)看SA輸出的日志中寫(xiě)為_(kāi)klass而在我的圖示上寫(xiě)為_(kāi)metadata的這個(gè)域。
在HotSpot的C++代碼里,oopDesc是所有放在GC堆上的對(duì)象的頂層類,它的成員就構(gòu)成了對(duì)象頭。HotSpot在C++代碼中用instanceOopDesc類來(lái)表示Java對(duì)象,而該類繼承oopDesc,所以HotSpot中的Java對(duì)象也自然擁有oopDesc所聲明的頭部。
hotspot/src/share/vm/oops/oop.hpp:
C++代碼 
class oopDesc {
private:
volatile markOop  _mark;
union _metadata {
wideKlassOop    _klass;
narrowOop       _compressed_klass;
} _metadata;
};
_metadata與前面提過(guò)的_mark一同構(gòu)成了對(duì)象頭。
_metadata是個(gè)union,為了能兼容32位、64位與開(kāi)了壓縮指針(CompressedOops)等幾種情況。無(wú)論是這個(gè)union中的_klass還是_compressed_klass域,它們都是用于指向一個(gè)描述該對(duì)象的klass對(duì)象的指針。SA的API屏蔽了普通指針與壓縮指針之間的差異,所以就直接把_metadata._klass稱為了_klass。
對(duì)象頭的格式是固定的,而對(duì)象自身內(nèi)容的布局則由HotSpot根據(jù)一定規(guī)則來(lái)決定。Java類在被HotSpot加載時(shí),其對(duì)象實(shí)例的布局與類自身的布局都會(huì)被計(jì)算出來(lái)。這個(gè)計(jì)算規(guī)則有機(jī)會(huì)以后再詳細(xì)寫(xiě)。
現(xiàn)在來(lái)看看"main"這個(gè)String對(duì)象實(shí)例自身的域都是些什么。
value:指向真正保存字符串內(nèi)容的對(duì)象的引用。留意Java里String并不把真正的字符內(nèi)容直接存在自己里面,而是引用一個(gè)char[]對(duì)象來(lái)承載真正的存儲(chǔ)。
從Java一側(cè)看value域的類型是char[],而從HotSpot的C++代碼來(lái)看它就是個(gè)普通的指針而已。它當(dāng)前值是0x7100b158,指向一個(gè)char[]對(duì)象的起始位置。
offset:字符串的內(nèi)容從value指向的char[]中的第幾個(gè)字符開(kāi)始算(0-based)。int型,32位帶符號(hào)整數(shù),這從Java和C++來(lái)看都差不多。當(dāng)前值為0。
count:該字符串的長(zhǎng)度,或者說(shuō)包含的UTF-16字符的個(gè)數(shù)。類型同上。當(dāng)前值為4,說(shuō)明該字符串有4個(gè)UTF-16字符。
hash:緩存該String對(duì)象的哈希值的成員域。類型同上。當(dāng)前值為0,說(shuō)明該實(shí)例的String.hashCode()方法尚未被調(diào)用過(guò),因而尚未緩存住該字符串的哈希值。
String對(duì)象的成員域都走過(guò)一遍了,來(lái)看看value所指向的對(duì)象狀況。
Log代碼 
[C @ 0x7100b158 (object size = 24)
- _mark:    {0} :1
- _klass:   {4} :TypeArrayKlass for [C @ 0x70e60440
- _length:  {8} :4
- 0:    {12} :m
- 1:    {14} :a
- 2:    {16} :i
- 3:    {18} :n
這就是"main"字符串的value所引用的char[]的日志。
[C 是char[]在JVM中的內(nèi)部名稱。
在@符號(hào)之后的0x7100b158是該對(duì)象的起始地址。
該對(duì)象占用GC堆的大小是24字節(jié)。留意了哦。
看看它的成員域。
_mark與_klass構(gòu)成的對(duì)象頭就不重復(fù)介紹了??梢粤粢獾氖窃仡愋蜑樵碱愋停╞oolean、char、short、int、long、float、double)的數(shù)組在HotSpot的C++代碼里是用typeArrayOopDesc來(lái)表示的;這里的char[]也不例外。描述typeArrayOopDesc的klass對(duì)象是typeArrayKlass類型的,所以可以看到日志里_klass的值寫(xiě)著TypeArrayKlass for [C。
接下來(lái)是_length域。HotSpot中,數(shù)組對(duì)象比普通對(duì)象的頭要多一個(gè)域,正是這個(gè)描述數(shù)組元素個(gè)數(shù)的_length。Java語(yǔ)言中數(shù)組的.length屬性、JVM字節(jié)碼中的arraylength要取的也正是這個(gè)值。
日志中的這個(gè)數(shù)組對(duì)象有4個(gè)字符,所以_length值為4。
再后面就是數(shù)組的內(nèi)容了。于是該char[]在內(nèi)存中的布局是:
-----------------------(+0) | _mark | -----------------------(+4) | _metadata | -----------------------(+8) | 數(shù)組長(zhǎng)度 length | -----------------------(+12) | char[0] | char[1] | -----------------------(+16) | char[2] | char[3] | -----------------------(+20) | 填充0 | -----------------------
Java的char是UTF-16字符,寬度是16位/2字節(jié);4個(gè)字符需要8字節(jié),加上對(duì)象頭的4*3=12字節(jié),總共需要20字節(jié)。但該char[]卻占用了GC堆上的24字節(jié),正是因?yàn)榍懊嫣岬降臄?shù)據(jù)對(duì)齊要求——HotSpot要求GC堆上的對(duì)象是8字節(jié)對(duì)齊的,20向上找最近的8的倍數(shù)就是24了。用于對(duì)齊的這部分會(huì)被填充為0。
"main"對(duì)象的value指向的char[]也介紹過(guò)了,回過(guò)頭來(lái)看看它的_metadata._klass所指向的klass對(duì)象又是什么狀況。
從HotSpot的角度來(lái)看,klass就是用于描述GC堆上的對(duì)象的對(duì)象;如果一個(gè)對(duì)象的大小、域的個(gè)數(shù)與類型等信息不固定的話,它就需要特定的klass對(duì)象來(lái)描述。
instanceOopDesc用于表示Java對(duì)象,instanceKlass用于描述它,但自身卻又有些不固定的信息需要被描述,因而又有instanceKlassKlass;如此下去會(huì)沒(méi)完沒(méi)了,所以有個(gè)klassKlass作為這個(gè)描述鏈上的終結(jié)符。
klass的關(guān)系圖:
(圖片來(lái)源)
回到foo.txt日志文件上來(lái),找到"main"對(duì)象的_klass域所引用的instanceKlass對(duì)象:
Log代碼 
InstanceKlass for java/lang/String @ 0x70e6c6a0 (object size = 384)
- _mark:    {0} :1
- _klass:   {4} :InstanceKlassKlass @ 0x70e60168
- _java_mirror:     {60} :Oop for java/lang/Class @ 0x70e77760
- _super:   {64} :InstanceKlass for java/lang/Object @ 0x70e65af8
- _size_helper:     {12} :6
- _name:    {68} :#java/lang/String @ 0x70e613e8
- _access_flags:    {84} :134217777
- _subklass:    {72} :null
- _next_sibling:    {76} :InstanceKlass for java/lang/CharSequence @ 0x70e680e8
- _alloc_count:     {88} :0
- _array_klasses:   {112} :ObjArrayKlass for InstanceKlass for java/lang/String @ 0x70ef6298
- _methods:     {116} :ObjArray @ 0x70e682a0
- _method_ordering:     {120} :[I @ 0x70e61330
- _local_interfaces:    {124} :ObjArray @ 0x70e67998
- _transitive_interfaces:   {128} :ObjArray @ 0x70e67998
- _nof_implementors:    {268} :0
- _implementors[0]:     {164} :null
- _implementors[0]:     {168} :null
- _fields:  {132} :[S @ 0x70e68230
- _constants:   {136} :ConstantPool for java/lang/String @ 0x70e65c38
- _class_loader:    {140} :null
- _protection_domain:   {144} :null
- _signers:     {148} :null
- _source_file_name:    {152} :#String.java @ 0x70e67980
- _inner_classes:   {160} :[S @ 0x70e6c820
- _nonstatic_field_size:    {196} :4
- _static_field_size:   {200} :4
- _static_oop_field_size:   {204} :2
- _nonstatic_oop_map_size:  {208} :1
- _is_marked_dependent:     {212} :0
- _init_state:  {220} :5
- _vtable_len:  {228} :5
- _itable_len:  {232} :9
- serialVersionUID:     {368} :-6849794470754667710
- serialPersistentFields:   {360} :ObjArray @ 0x74e882c8
- CASE_INSENSITIVE_ORDER:   {364} :Oop for java/lang/String$CaseInsensitiveComparator @ 0x74e882c0
還記得上文提到過(guò)的String類的3個(gè)靜態(tài)變量么?有沒(méi)有覺(jué)得有什么眼熟的地方?
沒(méi)錯(cuò),在HotSpot中,Java類的靜態(tài)變量就是作為該類對(duì)應(yīng)的instanceKlass的實(shí)例變量出現(xiàn)的。上面的日志里最后三行描述了String的靜態(tài)變量所在。
這是件非常自然的事:類用于描述對(duì)象,類自身也是對(duì)象,有用于描述自身的類;某個(gè)類的所謂“靜態(tài)變量”就是該類對(duì)象的實(shí)例變量。很多對(duì)象系統(tǒng)都是這么設(shè)計(jì)的。HotSpot的這套o(hù)op體系(指“普通對(duì)象指針”,不是指“面向?qū)ο缶幊獭保├^承自Strongtalk,實(shí)際上反而比暴露給Java的對(duì)象模型顯得更加面向?qū)ο笠恍?div style="height:15px;">
HotSpot并不把instanceKlass暴露給Java,而會(huì)另外創(chuàng)建對(duì)應(yīng)的java.lang.Class對(duì)象,并將后者稱為前者的“Java鏡像”,兩者之間互相持有引用。日志中的_java_mirror便是該instanceKlass對(duì)Class對(duì)象的引用。
鏡像機(jī)制被認(rèn)為是良好的面向?qū)ο蟮姆瓷渑c元編程設(shè)計(jì)的重要機(jī)制。Gilad Bracha與David Ungar還專門(mén)寫(xiě)了篇論文來(lái)闡述此觀點(diǎn),參考Mirrors: Design Principles for Meta-level Facilities of Object-Oriented Programming Languages。
順帶把"main"對(duì)象的_klass鏈上余下的兩個(gè)對(duì)象的日志也貼出來(lái):
Log代碼 
InstanceKlassKlass @ 0x70e60168 (object size = 120)
- _mark:    {0} :1
- _klass:   {4} :KlassKlass @ 0x70e60000
- _java_mirror:     {60} :Oop for java/lang/Class @ 0x70e76f20
- _super:   {64} :null
- _size_helper:     {12} :0
- _name:    {68} :null
- _access_flags:    {84} :0
- _subklass:    {72} :null
- _next_sibling:    {76} :null
- _alloc_count:     {88} :0
所有instanceKlass對(duì)象都是被這個(gè)instanceKlassKlass對(duì)象所描述的。
Log代碼 
KlassKlass @ 0x70e60000 (object size = 120)
- _mark:    {0} :1
- _klass:   {4} :KlassKlass @ 0x70e60000
- _java_mirror:     {60} :Oop for java/lang/Class @ 0x70e76e00
- _super:   {64} :null
- _size_helper:     {12} :0
- _name:    {68} :null
- _access_flags:    {84} :0
- _subklass:    {72} :null
- _next_sibling:    {76} :null
- _alloc_count:     {88} :0
而所有*KlassKlass對(duì)象都是被這個(gè)klassKlass對(duì)象所描述的。
klass對(duì)象的更詳細(xì)的介紹也留待以后再寫(xiě)吧~至少得找時(shí)間寫(xiě)寫(xiě)instanceKlass與vtable、itable的故事。
嘛,今天的廢話到此結(jié)束 ^_^
希望這帖能解答先前關(guān)于java里面的全局變量的內(nèi)存分配一帖中的疑問(wèn)。也希望大家能多多支持高級(jí)語(yǔ)言虛擬機(jī)圈子,有什么HLL VM相關(guān)的話題想討論的歡迎來(lái)轉(zhuǎn)轉(zhuǎn)~
foo.zip (1.7 MB)
描述: 文中例子的輸出
下載次數(shù): 45
查看圖片附件
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
HotSpot虛擬機(jī)對(duì)象探秘
GC分代年齡為什么是15?
JVM總結(jié) ----JVM體系結(jié)構(gòu)
Java系列:JVM中的OopMap(zz)
為什么我們選擇 Java 語(yǔ)言開(kāi)發(fā)高頻交易系統(tǒng)
Java對(duì)象結(jié)構(gòu)【面試+工作】
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服