JVM筆記:Java虛擬機(jī)的常量池

這篇文章主要是做一個(gè)總結(jié)烘贴,將查找到相關(guān)的資料自己做一個(gè)整理,最后會(huì)列出查找過的相關(guān)資料,感興趣的可以去翻一翻刺洒。

常量池

  • class文件常量池(class constant pool)

    常量池可以理解為Class文件之中的資源倉庫,它是Class文件結(jié)構(gòu)中與其他項(xiàng)目關(guān)聯(lián)最多的數(shù)據(jù)類型亚斋,包含了類也是占用Class文件中第一個(gè)出現(xiàn)的表類型數(shù)據(jù)項(xiàng)目作媚。

    常量池中主要存放兩大類常量:字面量(Literal)和符號(hào)引用(Symbolic References)。字面量比較接近于Java語言層面的常量概念帅刊,如文本字符串、聲明為final的常量值等漂问。而符號(hào)引用則屬于編譯原理方面的概念赖瞒,包含了下面三類常量:

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

    類和接口的全限定名,例如:com/example/demo/Demo.class

    字段的名稱和描述符蚤假,例如:Field a:[Ljava/lang/String

    方法的名稱和描述符栏饮,例如:Method java/lang/String."<init>":(Ljava/lang/String;)V

    后兩個(gè)是字節(jié)碼指令,不懂得可以查閱下相關(guān)資料(TODO)

    可以通過查看字節(jié)碼的形式來查看Class的常量池的內(nèi)容磷仰,因?yàn)槭窃诰幾g時(shí)產(chǎn)生的袍嬉,也可以稱為靜態(tài)常量池

public class Main {
   private int a=1;
   private int b=1;
   private Aload c=new Aload();
   private String [] d =new String[10];
   public static void main(String[] args) {

   }
}
字節(jié)碼:
public class com.verzqli.snake.Main
 minor version: 0
 major version: 51
 flags: ACC_PUBLIC, ACC_SUPER
Constant pool: //這里就是class文件的常量池
  #1 = Methodref          #10.#30        // java/lang/Object."<init>":()V
  #2 = Fieldref           #9.#31         // com/verzqli/snake/Main.a:I
  #3 = Fieldref           #9.#32         // com/verzqli/snake/Main.b:I
  #4 = Class              #33            // com/verzqli/snake/Aload
  #5 = Methodref          #4.#30         // com/verzqli/snake/Aload."<init>":()V
  #6 = Fieldref           #9.#34         // com/verzqli/snake/Main.c:Lcom/verzqli/snake/Aload;
  #7 = Class              #35            // java/lang/String
  #8 = Fieldref           #9.#36         // com/verzqli/snake/Main.d:[Ljava/lang/String;
  #9 = Class              #37            // com/verzqli/snake/Main
 #10 = Class              #38            // java/lang/Object
 #11 = Utf8               a
 #12 = Utf8               I
 #13 = Utf8               b
 #14 = Utf8               c
 #15 = Utf8               Lcom/verzqli/snake/Aload;
 #16 = Utf8               d
 #17 = Utf8               [Ljava/lang/String;
 #18 = Utf8               <init>
 #19 = Utf8               ()V
 #20 = Utf8               Code
 #21 = Utf8               LineNumberTable
 #22 = Utf8               LocalVariableTable
 #23 = Utf8               this
 #24 = Utf8               Lcom/verzqli/snake/Main;
 #25 = Utf8               main
 #26 = Utf8               ([Ljava/lang/String;)V
 #27 = Utf8               args
 #28 = Utf8               SourceFile
 #29 = Utf8               Main.java
 #30 = NameAndType        #18:#19        // "<init>":()V
 #31 = NameAndType        #11:#12        // a:I
 #32 = NameAndType        #13:#12        // b:I
 #33 = Utf8               com/verzqli/snake/Aload
 #34 = NameAndType        #14:#15        // c:Lcom/verzqli/snake/Aload;
 #35 = Utf8               java/lang/String
 #36 = NameAndType        #16:#17        // d:[Ljava/lang/String;
 #37 = Utf8               com/verzqli/snake/Main
 #38 = Utf8               java/lang/Object
  • 運(yùn)行時(shí)常量池

    當(dāng)java文件被編譯成class文件之后,就會(huì)生成上面的常量池伺通,在Class文件中描述的各種信息箍土,最終都需要加載到虛擬機(jī)中之后才能運(yùn)行和使用。
    類從被加載到虛擬機(jī)內(nèi)存中開始罐监,到卸載出內(nèi)存位置吴藻,他的生命周期包括:加載(Loading)、驗(yàn)證(Verification)弓柱、準(zhǔn)備(Preparation)沟堡、解析(Resolution)、初始化(Initalization)矢空、使用(Using)和卸載(Unloading),其中驗(yàn)證航罗、準(zhǔn)備、解析三個(gè)部分統(tǒng)稱Wie連接(Linking)屁药。

    而當(dāng)類加載到內(nèi)存中后伤哺,JVM就會(huì)將Class常量池中的內(nèi)容存放到運(yùn)行時(shí)常量池中,由此可知者祖,運(yùn)行時(shí)常量池也是每個(gè)類都有一個(gè)立莉。在解析過程中需要將常量池中所有的符號(hào)引用(classes、interfaces七问、fields蜓耻、methods referenced in the constant pool)轉(zhuǎn)為直接引用(得到類或者字段、方法在內(nèi)存中的指針或者偏移量械巡,以便直接調(diào)用該方法)刹淌。直接引用可以是內(nèi)存中,直接指向目標(biāo)的指讥耗、相對(duì)偏移量有勾,或是一個(gè)能間接定位到目標(biāo)的句柄,解析的這個(gè)階段其實(shí)就是將符號(hào)引用轉(zhuǎn)換為可以直接定位對(duì)象等在內(nèi)存中的位置的直接引用古程。

    運(yùn)行時(shí)常量池位于JVM規(guī)范的方法區(qū)中蔼卡,在Java8以前,位于永生代挣磨;Java8之后位于元空間雇逞。

  • 全局字符串常量池(string pool / string literal pool)

    全局字符串池里的內(nèi)容是在類加載完成,經(jīng)過驗(yàn)證茁裙,準(zhǔn)備階段之后在堆中生成字符串對(duì)象實(shí)例塘砸,然后將該字符串對(duì)象實(shí)例的引用值存到string pool中。在HotSpot中具體實(shí)現(xiàn)string pool這一功能的是StringTable類晤锥,它是一個(gè)哈希表掉蔬,里面存的是key(字面量“abc”, 即駐留字符串)-value(字符串"abc"實(shí)例對(duì)象在堆中的引用)鍵值對(duì)廊宪,StringTable本身存在本地內(nèi)存(native memory)中。

    StringTable在每個(gè)HotSpot VM的實(shí)例只有一份女轿,被所有的類共享(享元模式)箭启。在Java7的時(shí)候?qū)⒆址A砍匾频搅硕牙铮瑫r(shí)里面也不在存放對(duì)象(Java7以前被intern的String對(duì)象存放于永生代谈喳,所以很容易造成OOM)册烈,而是存放堆上String實(shí)例對(duì)象的引用。

那么字符串常量池中引用的String對(duì)象是在什么時(shí)候創(chuàng)建的呢婿禽?在JVM規(guī)范里明確指定resolve階段可以是lazy的赏僧,即在需要進(jìn)行該符號(hào)引用的解析時(shí)才去解析它,這樣的話扭倾,可能該類都已經(jīng)初始化完成了淀零,如果其他的類鏈接到該類中的符號(hào)引用,需要進(jìn)行解析膛壹,這個(gè)時(shí)候才會(huì)去解析驾中。

這時(shí)候就需要ldc這個(gè)字節(jié)碼指令,其作用是將int模聋、float或String型常量值從常量池中推送至棧頂,如下面這個(gè)例子肩民。

public class Main {
    public static void main(String[] args) {
      String a="B";
    }
}
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #2                  // String B
         2: astore_1
         3: return
      LineNumberTable:
        line 14: 0
        line 15: 3
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;
            3       1     1     a   Ljava/lang/String;
}

在main方法的字節(jié)碼中使用ldc將字符串“B”推到棧頂,然后賦值給局部變量a,最后退出链方。

根據(jù)上面說的持痰,在類加載階段,這個(gè) resolve 階段( constant pool resolution )是lazy的祟蚀。換句話說并沒有真正的對(duì)象工窍,字符串常量池里自然也沒有,那么ldc指令還怎么把人推送至棧頂前酿?或者換一個(gè)角度想患雏,既然resolve 階段是lazy的,那總有一個(gè)時(shí)候它要真正的執(zhí)行吧罢维,是什么時(shí)候淹仑?執(zhí)行l(wèi)dc指令就是觸發(fā)這個(gè)lazy resolution動(dòng)作的條件

ldc字節(jié)碼在這里的執(zhí)行語義是:到當(dāng)前類的運(yùn)行時(shí)常量池(runtime constant pool言津,HotSpot VM里是ConstantPool + ConstantPoolCache)去查找該index對(duì)應(yīng)的項(xiàng)攻人,如果該項(xiàng)尚未resolve則resolve之,并返回resolve后的內(nèi)容悬槽。

在遇到String類型常量時(shí),resolve的過程如果發(fā)現(xiàn)StringTable已經(jīng)有了內(nèi)容匹配的java.lang.String的引用瞬浓,則直接返回這個(gè)引用初婆,反之,如果StringTable里尚未有內(nèi)容匹配的String實(shí)例的引用,則會(huì)在Java堆里創(chuàng)建一個(gè)對(duì)應(yīng)內(nèi)容的String對(duì)象磅叛,然后在StringTable記錄下這個(gè)引用屑咳,并返回這個(gè)引用出去”浊伲可見兆龙,ldc指令是否需要?jiǎng)?chuàng)建新的String實(shí)例,全看在第一次執(zhí)行這一條ldc指令時(shí)敲董,StringTable是否已經(jīng)記錄了一個(gè)對(duì)應(yīng)內(nèi)容的String的引用紫皇。

public class Main {
    String a="b";
    public static void main(String[] args) {
    }
}

public com.verzqli.snake.Main();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: ldc           #2                  // String b
         7: putfield      #3                  // Field a:Ljava/lang/String;
        10: return
      LineNumberTable:
        line 12: 0
        line 13: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   Lcom/verzqli/snake/Main;

上面例子執(zhí)行完main方法后,“b”就不會(huì)進(jìn)入字符串常量池腋寨。因?yàn)镾tring a = "b"是Main類的成員變量聪铺,成員變量只有在執(zhí)行到構(gòu)造方法的時(shí)候才會(huì)初始化。

往細(xì)講萄窜,只有執(zhí)行了ldc指令的字符串才會(huì)進(jìn)入字符串常量池

至于ldc指令的工作原理可以看這篇文章铃剔。

String.intern()

當(dāng)一個(gè)字符串對(duì)象調(diào)用這個(gè)intern方法時(shí),如果該字符串常量池中不包含該對(duì)象引用查刻,也即StringTable不包含該對(duì)象字面量和引用時(shí)键兜,將該字符串對(duì)象引用存入字符串常量中 ,同時(shí)返回該地址穗泵。這樣做的目的是為了提升性能普气,降低開銷,后續(xù)如果定義相同字面量的字符串即可返回該引用(內(nèi)存地址)火欧,不必再在堆上創(chuàng)建字符串實(shí)例棋电。

  • 實(shí)例(以下實(shí)例環(huán)境為JDK7以后)

          String a="c";
          String b = new String("c");
          System.out.println("a==b.intern()="+(a==b.intern()));
          System.out.println("b==b.intern()="+(b==b.intern()));
          
          結(jié)果:
          a==b.intern()=true
          b==b.intern()=false
    

    類加載階段,什么都沒干苇侵。

    然后運(yùn)行main方法赶盔,創(chuàng)建“c”對(duì)象 ,假設(shè)其地址為0xeee榆浓,將其加入字符串常量池于未。隨后在堆上創(chuàng)建了String對(duì)象b,假設(shè)其地址為0xfff陡鹃。

    這里b.intern()檢測(cè)到了字符串常量池中包含“c”這個(gè)字符串引用烘浦,所以其返回的是0xeee,而b指向的依舊是0xfff萍鲸,所以第一個(gè)為true闷叉,第二個(gè)為false

         String a = new String("hellow") + new String("orld");
         String b = new String("hello") + new String("world");
         System.out.println("a==a.intern()="+(a==a.intern()));
         System.out.println("a==b.intern()="+(a==b.intern()));
         System.out.println("b==b.intern()="+(b==b.intern()));
    
       結(jié)果:
      a==b.intern()=true
      a==b.intern()=true
      b==b.intern()=false
    

    類加載階段脊阴,什么都沒干握侧。

    然后運(yùn)行main方法蚯瞧,創(chuàng)建“hellow”,"orld"對(duì)象,并放入字符串常量池品擎。然后會(huì)創(chuàng)建一個(gè)"helloworld"對(duì)象埋合,沒有放入字符串常量池,a指向這個(gè)"helloworld"對(duì)象(0xeee)萄传。

    接著創(chuàng)建“hello”,"world"對(duì)象甚颂,同樣也創(chuàng)建一個(gè)"helloworld"對(duì)象,也沒有放入字符串常量池秀菱,b指向這個(gè)"helloworld"對(duì)象地址(0xfff)振诬。

    這時(shí)候第一個(gè)判斷,字符串常量池沒有“helloworld”這個(gè)字符串對(duì)象引用答朋,所以將a的引用(0xeee)放入字符串常量池贷揽,也就是說池子中的引用和a的引用(0xeee)是一樣的,所以a==a.intern()梦碗。

    b.intern()時(shí)因?yàn)樯弦徊孔址A砍刂幸呀?jīng)有了這個(gè)“helloworld”的引用禽绪,所以他返回回去的引用(0xeee)就是a的引用,所以a==b.intern()洪规。

    從上面可以清楚的知道b.intern()返回的是0xfff印屁,而b引用地址為0xfff,所以b!=b.intern()斩例。

        //        String a1="helloworld";
        String a = new String("hello")+new String("world");
        System.out.println("a==a=" + (a == a.intern()));
    

    這里的結(jié)果如果a1沒有被注釋則為false雄人,注釋了則為true亚隙,原理同上震桶,可以自己腦補(bǔ)一下庇谆。

  • JVM對(duì)字符串的優(yōu)化

          String a = "hello";
        String b = a+"world";
        String c = "helloworld";
        String d = "hello"+"world";
        System.out.println(b==c); false
        System.out.println(d==c); true
        System.out.println(b==d); false
        
            Code:
      stack=3, locals=5, args_size=1
         0: ldc           #4                  // String hello //ldc指令創(chuàng)建字符串對(duì)象“hello”
         2: astore_1                          // 將a從放入局部變量表(第一個(gè)局部變量映企,第0個(gè)是this)
         3: new           #5                  // class java/lang/StringBuilder //創(chuàng)建StringBuilder對(duì)象
         6: dup                               // 復(fù)制棧頂數(shù)據(jù)(創(chuàng)建StringBuilder對(duì)象)壓入棧中
         7: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V 
        10: aload_1                           // 從局部變量中載入a到棧中
        11: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; //可以看出字符串相加在字節(jié)碼里就是StringBuilder的append
        14: ldc           #8                  // String world /ldc指令創(chuàng)建字符串對(duì)象“world”
        16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;//繼續(xù)append
        19: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String; //相加完畢,隱形的調(diào)用toString生成String對(duì)象返回
        22: astore_2                          // 將b放入局部變量表(第二個(gè)局部變量)   
        23: ldc           #10                 // String helloworld  //ldc指令創(chuàng)建字符串對(duì)象“helloworld”
        25: astore_3                          // 將c放入局部變量表(第三個(gè)局部變量) 
        26: ldc           #10                 // String helloworld  //這里字符串常量池中已經(jīng)包含了helloworld杰捂,就不會(huì)再創(chuàng)建翰灾,直接引用哮肚,而且這個(gè)helloworld是"hello"+"world"拼接的停局,這就是JVM對(duì)字符串的優(yōu)化
        28: astore        4                   // 將d放入局部變量表(第四個(gè)局部變量) 
        30: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream; //調(diào)用靜態(tài)方法打印
        33: aload_2                           // 從局部變量表加載b入棧
        34: aload_3                           // 從局部變量表加載c入棧
        35: if_acmpne     42                  // 比較兩個(gè)對(duì)象的引用類型 下面四行就是一個(gè)if else 語句很钓,如果相等就直接doto打印結(jié)果,
        38: iconst_1                          // 獲得兩個(gè)引用是否相等的結(jié)果(true為1董栽,false為0)码倦,將1入棧
        39: goto          43                  // 跳轉(zhuǎn)到43行 直接打印出結(jié)果
        42: iconst_0                          // 兩引用不相等,將0入棧 
        43: invokevirtual #12                 // Method java/io/PrintStream.println:(Z)V
        46: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
        后續(xù)都是相同的意思锭碳,這里就不注釋了袁稽。
        49: aload         4
        51: aload_3
        52: if_acmpne     59
        55: iconst_1
        56: goto          60
        59: iconst_0
        60: invokevirtual #12                 // Method java/io/PrintStream.println:(Z)V
        63: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
        66: aload_2
        67: aload         4
        69: if_acmpne     76
        72: iconst_1
        73: goto          77
        76: iconst_0
        77: invokevirtual #12                 // Method java/io/PrintStream.println:(Z)V
        80: return
    

    從上面的字節(jié)碼
    可以看出字符串的相加其實(shí)是new了一個(gè)StringBuilder來進(jìn)行append,a和b不相等就是因?yàn)檫@已經(jīng)是兩個(gè)不同的對(duì)象了擒抛,引用也不相等运提。后續(xù)c和d相等是因?yàn)镴VM對(duì)純字符串想加做了調(diào)優(yōu)蝗柔,會(huì)在字節(jié)碼中把他們直接相加后的值賦給局部變量闻葵,所以c和d指向的是同一個(gè)字符串民泵。

    
        String a= "a";
        for (int i = 0; i < 3; i++) {
            a+="b";
        }
        
        Code:
      stack=2, locals=3, args_size=1
         0: ldc           #4                  // String a
         2: astore_1
         3: iconst_0
         4: istore_2
         5: iload_2
         6: iconst_3
         7: if_icmpge     36
        10: new           #5                  // class java/lang/StringBuilder
        13: dup
        14: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
        17: aload_1
        18: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        21: ldc           #2                  // String b
        23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        29: astore_1
        30: iinc          2, 1
        33: goto          5
        36: return
    

    對(duì)于for循環(huán)中的字符串相加(3到33行就是for循環(huán)的內(nèi)容),JVM就沒有優(yōu)化了槽畔,每次相加都是重新創(chuàng)建了StringBuilder栈妆,開銷就是一個(gè)StringBuilder的幾何倍數(shù)那么大,因而在循環(huán)中使用StringBuilder的append來替代直接相加厢钧。

  • 總結(jié)

    除了日常的如果覺得文章有錯(cuò)誤鳞尔,歡迎指出并交流。這里問一個(gè)問題早直,后續(xù)如果知道了再刪除:字符串常量池和StringTable是一個(gè)東西嗎寥假,兩者都是存的字符串引用,但是R大說過StringTable是存于本地內(nèi)存(native memory)霞扬,但是看過的文章都說的是字符串常量池位于java堆中糕韧,希望有知道的大佬可以告知一下。

  • 引用:

    徹底搞懂string常量池和intern

    JVM 常量池中存儲(chǔ)的是對(duì)象還是引用呢喻圃?

    Java String實(shí)例的創(chuàng)建和常量池的關(guān)系及intern方法

    Java 中new String("字面量") 中 "字面量" 是何時(shí)進(jìn)入字符串常量池的?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萤彩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子斧拍,更是在濱河造成了極大的恐慌雀扶,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肆汹,死亡現(xiàn)場(chǎng)離奇詭異愚墓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)昂勉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門浪册,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人硼啤,你說我怎么就攤上這事议经。” “怎么了谴返?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵煞肾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我嗓袱,道長(zhǎng)籍救,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任渠抹,我火速辦了婚禮蝙昙,結(jié)果婚禮上闪萄,老公的妹妹穿的比我還像新娘。我一直安慰自己奇颠,他們只是感情好败去,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著烈拒,像睡著了一般圆裕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荆几,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天吓妆,我揣著相機(jī)與錄音,去河邊找鬼吨铸。 笑死行拢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诞吱。 我是一名探鬼主播舟奠,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼狐胎!你這毒婦竟也來了鸭栖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤握巢,失蹤者是張志新(化名)和其女友劉穎晕鹊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暴浦,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溅话,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歌焦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片飞几。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖独撇,靈堂內(nèi)的尸體忽然破棺而出屑墨,到底是詐尸還是另有隱情,我是刑警寧澤纷铣,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布卵史,位于F島的核電站,受9級(jí)特大地震影響搜立,放射性物質(zhì)發(fā)生泄漏以躯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忧设。 院中可真熱鬧刁标,春花似錦、人聲如沸址晕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斩箫。三九已至吏砂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乘客,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工淀歇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留易核,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓浪默,卻偏偏與公主長(zhǎng)得像牡直,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纳决,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • ??需要說明的一點(diǎn)是碰逸,這篇文章是以《深入理解Java虛擬機(jī)》第二版這本書為基礎(chǔ)的,這里假設(shè)大家已經(jīng)了解了JVM的運(yùn)...
    Geeks_Liu閱讀 14,013評(píng)論 5 44
  • 談起String阔加,大家肯定一定都不陌生饵史,肯定也都使用過,出去面試的時(shí)候也有碰到過問相關(guān)原理的胜榔。今天就結(jié)合Strin...
    miaoLoveCode閱讀 1,915評(píng)論 10 28
  • JVM中的字符串常量池是個(gè)有些玄幻的玩意兒胳喷,關(guān)于它的細(xì)節(jié),各類書籍和網(wǎng)站上眾說紛紜夭织。本文試圖參考盡量權(quán)威的資料吭露,找...
    LittleMagic閱讀 3,082評(píng)論 8 20
  • 這篇文章解釋了Java 虛擬機(jī)(JVM)的內(nèi)部架構(gòu)。下圖顯示了遵守Java SE 7 規(guī)范的典型的 JVM 核心內(nèi)...
    飲墨饗書閱讀 659評(píng)論 0 1
  • 突然發(fā)現(xiàn)尊惰,一天可以生幾下氣讲竿,也可以不說一句話。 現(xiàn)在幾乎沒有吸引我的地方了弄屡,我通通都放棄题禀。 不想再去...
    山坑游子閱讀 182評(píng)論 0 0