常量池和StringTable

2024-01-11 03:12
文章标签 常量 stringtable

本文主要是介绍常量池和StringTable,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 运行时常量池

  • 常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息

  • 运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

2 StringTable(串池)

先看一道面试题:

String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();
// 问
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
// 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢
System.out.println(x1 == x2);

答案是:false true true false(调换后true)

上面程序使用javap -v反编译后得到JVM指令如下:

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=4, locals=9, args_size=10: ldc           #2                  // String a2: astore_13: ldc           #3                  // String b5: astore_26: ldc           #4                  // String ab8: astore_39: new           #5                  // class java/lang/StringBuilder12: dup13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V16: aload_117: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;20: aload_221: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;27: astore        429: ldc           #4                  // String ab31: astore        533: aload         435: invokevirtual #9                  // Method java/lang/String.intern:()Ljava/lang/String;38: astore        640: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;43: aload_344: aload         446: if_acmpne     5349: iconst_150: goto          5453: iconst_054: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V57: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;60: aload_361: aload         563: if_acmpne     7066: iconst_167: goto          7170: iconst_071: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V74: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;77: aload_378: aload         680: if_acmpne     8783: iconst_184: goto          8887: iconst_088: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V91: new           #5                  // class java/lang/StringBuilder94: dup95: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V98: new           #12                 // class java/lang/String101: dup102: ldc           #13                 // String c104: invokespecial #14                 // Method java/lang/String."<init>":(Ljava/lang/String;)V107: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;110: new           #12                 // class java/lang/String113: dup114: ldc           #15                 // String d116: invokespecial #14                 // Method java/lang/String."<init>":(Ljava/lang/String;)V119: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;122: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;125: astore        7127: ldc           #16                 // String cd129: astore        8131: aload         7133: invokevirtual #9                  // Method java/lang/String.intern:()Ljava/lang/String;136: pop137: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;140: aload         8142: aload         7144: if_acmpne     151147: iconst_1148: goto          152151: iconst_0152: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V155: return

分析:

s1引用的是串池中的常量"a"

s2引用的是串池中的常量"b"

s3引用的是编译时优化的"a"“b"拼接后的串池中的常量"ab”

s4引用的是堆中StringBuilder对象调用init方法初始化,并append"a",又append"b",最后调用toString得到的String对象

s5引用的是串池中的常量"ab"

s6,由于s4的对象内容"ab"在s3执行时就已经入池,因此返回串池中的"ab",即s3的地址

x2引用的是堆中StringBuilder对象调用init方法初始化,并append堆中创建的"c"和"d"String对象,最后调用toString得到的String对象

x1引用的是串池中的常量"cd"

x2.intern();执行完上一句后,此时串池中已有"cd",不会将x2放入串池,x2仍引用堆中的对象地址

注意1:若执行x2.intern();后再String x1 = “cd”;则两个变量引用的都是串池中的"cd"的地址

注意2:以上都是jdk1.8版本的答案,如果是jdk1.6,在String x2 = new String(“c”) + new String(“d”);后,先执行x2.intern();再String x1 = “cd”;分析为:x2.intern()将堆中对象拷贝到串池中,导致x1==x2结果为false

intern方法说明:

功能:将串池中还没有的字符串对象放入串池

1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回

1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回

StringTable总结

位置GC调优
1.8版本位于堆中
1.6版本只存在于老年代
1.8时触发minorGC
1.6时触发fullGC
增大堆内存的同时
适当增加StringTableSize桶个数可以减少寻址时的hash碰撞概率,从而节省读写时间
intern方法使对象入池复用(大量重复情况),可以节省大量创建新对象占用堆内存

这篇关于常量池和StringTable的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/592961

相关文章

从零开始学习JVM(七)- StringTable字符串常量池

1 概述 String应该是Java使用最多的类吧,很少有Java程序没有使用到String的。在Java中创建对象是一件挺耗费性能的事,而且我们又经常使用相同的String对象,那么创建这些相同的对象不是白白浪费性能吗。所以就有了StringTable这一特殊的存在,StringTable叫做字符串常量池,用于存放字符串常量,这样当我们使用相同的字符串对象时,就可以直接从StringTable

Java之常量的概念

Java之常量的概念 零基础学Java什么是常量常量的分类了解下常量池动动手练习题 零基础学Java Java学习交流 : V:study_51ctofx 什么是常量 常量:程序运行中,固定不变的量 两种表现形式: 字面常量和final修饰的常量 public static void main(String[] args){//其中 1 为字面常量,固定不变的量int

【Java String】简述String类比较和常量池内存分析

一、引出正题 String 类型对象进行比较时,我们一般使用 equals() 的方式进行值比较,但是有时候可能会出现 == 对象比较的方式。 在使用 == 比较的时候,往往是和String在JVM内存存储结构有关,这也引起了部分同学使用时的错误,那么接下来我们来详细分析一下此问题。 二、举例说明 1、new String("xx")都是在堆上创建字符串对象。当调用 intern() 方

Java虚拟机--方法区(运行时常量池)

文章引用: 深入理解Java虚拟机 https://blog.csdn.net/huangfan322/article/details/53220169 一 方法区描述 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息/常量//静态信息/即时编译器编译后的代码等数据.虽然Java虚拟机规范把方法区描述为堆的

golang-基础知识(变量、常量以及基础数据类型)

1. 变量 变量定义一般有以下几种方式 var name type表示定义一个名称为name,类型为type的变量var name1, name2, name3 type表示同时定义多个类型为type的变量var name type = value定义变量并初始化值var name1, name2, name3 type = value1, value2, vaule3定义多个变量并同时初始化

struts2 struts.xml常用常量配置

<constant name="struts.i18n.encoding" value="UTF-8" /> 指定Web应用的默认编码集,相当于调用HttpServletRequest的setCharacterEncoding方法 <constant name="struts.ui.theme" value="simple" /> 设置页面struts标签的样式     <consta

java内存分配,常量池,各种类型==比较

字符串内存分配: 首先: (1)String a="123"; (2)a="456"; String为final常量,会把字符串存入常量池,当第一步会先"123"放入常量池并分配内存地址,a为“123”的引用,即他的的内存地址为“123”的内存地址,第二步a的地址为“456”的地址      对于字符串,其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)

IDEA提示:java: 常量字符串过长

大家好,我是瑶山,今天聊聊java执行字符串过长的问题 起因 main方法测试一个上传人脸的请求,人脸图片使用Base64格式字符串,执行失败,提示:java: 常量字符串过长 在Java中,当你在main方法中直接使用一个字符串常量,并且这个字符串常量的长度超过了JVM默认的方法大小限制时,你可能会遇到“常量字符串过长”的错误。这个限制是编译器和JVM对于方法大小的内部限制,

关于不能改变字符串常量值的理解

char *buf = "hello World!"; //关于字符串常量值不能修改理解, 因为字符串定义在全局常量区,//下面这句就是尝试改变字符串的值, 所以该语句错误 strcpy(buf, "q345w4565467");//这句不是改变字符串的值, 是改变指针的指向,所以运行没有问题 buf = "q345w4565467";char buf[] = "hello Worl

5.struts.xml配置常量和Action处理流程

第五记:struts.xml配置常量和Action处理流程 (1)、常量设置         1-1:修改ation的后缀               将.action后缀改为.do:               <constant name="Struts.action.extension"  value="do"/>               可以修改访问多种后缀: