JVM基础篇-StringTable

news2024/12/27 0:10:15

StringTable

特性

  • 常量池中的字符串仅是符号,第一次用到时才变为对象

  • 利用串池的机制,来避免重复创建字符串对象

  • 字符串变量拼接的原理是 StringBuilder (1.8)

  • 字符串常量拼接的原理是编译期优化

  • 可以使用 intern 方法,主动将串池中还没有的字符串对象放入串池

    • 1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
    • 1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回
场景1
package com.vmware.jvm;

public class Demo1 {
    public static void main(String[] args) {
        String a="a";
        String b="b";
        String c="ab";
    }
}
  • 在JVM中会预先准备好一块内存空间 StringTable [] ,其内容为空 数据结构采用HashTable
  • 此时符号a、b、ab都还是常量池中的符号,还没有变为java字符串对象
  • ldc #2会将a符号变为a字符串对象,然后判断StringTable中是否存在字符串a,如果不存在则添加到StringTable中,否则直接使用StringTable中的串
  • ldc #3会将b符号变为b字符串对象 然后判断StringTable中是否存在字符串b,如果不存在则添加到StringTable中,否则直接使用StringTable中的串
  • ldc #4会将ab符号变为ab字符串对象 然后判断StringTable中是否存在字符串ab,如果不存在则添加到StringTable中,否则直接使用StringTable中的串
  • 执行结束后: StringTable [“a”,“b”,“ab”]

❗️ 注意:字符串不会预先加载到StringTable中,而是当使用该字符串时才会被加载,其行为为懒惰型

反编译代码

      stack=1, locals=4, args_size=1
         0: ldc           #2                  // String a  
         2: astore_1                                       
         3: ldc           #3                  // String b  
         5: astore_2                                       
         6: ldc           #4                  // String ab 
         8: astore_3                                       
         9: return
场景2
public class Demo1 {
    public static void main(String[] args) {
        String a = "a";
        String b = "b";
        String c = "ab";
        String d = a + b;
    }
}

反编译如下

9: new           #5                  // class java/lang/StringBuilder //new StringBuilder()
12: dup
13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V 调用无参构造方法
16: aload_1                           //从LocalVariableTable中加载1号槽的变量"a"
17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; //调用StringBuild().append("a")
20: aload_2                           //从LocalVariableTable中加载2号槽的变量"b"
21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;//调用StringBuild().append("b")
24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
//调用toString()方法  -> new String("ab");
27: astore        4                   //存储到LocalVariableTable4号槽

StringBuild toString方法源码

 	@Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

相当于

new StringBuild().append("a").append("b").toString();

调用new String(“ab”)后相当于在堆中创建了一个新的字符串对象,所以

d==c  //false d在堆中 c在StringTable中
编译期优化

javac会认为e的结果是确定的,所以进行了编译期优化

String e = "a" + "b";

反编译

 29: ldc           #4                  // String ab
  • 相当于直接从常量池中加载符号ab
c==e //true  c第一次被加载到StringTable中,e与c相同不会再次进入StringTable,e指向的地址与c的地址相同
字符串延迟加载证明

在这里插入图片描述

  • 可以使用IDEA开启debug模式后,使用内存检测功能,观察字符串的数量
package com.vmware.jvm;

public class Demo2 {
    public static void main(String[] args) {
        System.out.println();//2433
        System.out.println("a");//2434
        System.out.println("b");//2235
        System.out.println("c");//2436
        System.out.println("a");//2436
        System.out.println("b");//2436
        System.out.println("c");//2436
    }
}
  • 代码每执行一行,String的数量+1,说明字符串没有进行预加载
  • 第二次使用字符串时,String的数量没有增加
场景三
public class Demo3 {
    public static void main(String[] args) {
        String x="ab";
        String s = new String("a") + new String("b");//实际上利用StringBuild的append方法进行拼接,"a" "b"会被先加载到串池中 StringTable=["ab","a","b"]
        String s2 = s.intern();//入池失败   s2-> table."ab"  s-> heap."ab"  x-> table."ab"
        System.out.println(s == x);//false
        System.out.println(s2 == x);//true
    }
}
  • intern方法在jdk1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,并返回串池中的对象
  • 在jdk1.6中将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回
String s2 = s.intern();//s2 -> table  s-> heap
  • intern方法注释:调用 intern 方法时,如果池已包含与equals(Object)方法比较后相等的String字符串,则返回池中的字符串。否则,此String对象将添加到池中,并返回对此String对象的引用
问题
package com.vmware.jvm;

public class Demo4 {
    public static void main(String[] args) {
        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);//false  s3在编译期进行优化 s3="ab" 在StringTable中  s4=new StringBuild().append("a").append("b"),toString() 在堆中
        System.out.println(s3 == s5);//true s3进入StringTable s5发现StringTable中有"ab"则指向Table中的地址
        System.out.println(s3 == s6);//true  s4调用intern方法后入池失败,返回池中的"ab"所以 s6即为池中的"ab"

        String x2 = new String("c") + new String("d");
        String x1 = "cd";
        x2.intern();//将对象new String("cd")放入池中,入池失败
        //问 如果调换了后两行的位置呢,如果是jdk1.6呢
        System.out.println(x1 == x2);
        //jdk1.8 false x2指向堆,x2调用入池方法后入池失败 x2指向堆 x1指向StringTable
        //交换位置  x2入池成功,x2指向池中的cd  x1指向池中的c 所以为true
        //jdk1.6 首先在堆中new String("cd") 然后调用intern方法,会对堆中的对象拷贝一份入池,而x2仍然指向堆中的对象  x1发现池中有"cd"直接使用池中的对象,所以为false
    }
}
String Table的位置

在这里插入图片描述

  • jdk1.6:永久代
  • jdk1.7、1.8:堆内存

🔖 为什么要将StringTable从永久代移动到堆中?

因为永久代的内存只有当触发FullGC的时候才会回收,而堆内存在触发MinorGC的时候就会触发回收,由于StringTable使用比较频繁,所以JVM工程师对位置进行了移动

垃圾回收
package com.vmware.jvm;

/**
 * @apiNote StringTable垃圾回收延时
 * -Xmx10m:设置堆大小为10m
 * -XX:+PrintStringTableStatistics 打印StringTable信息
 * -XX:+PrintGCDetails -verbose:gc 打印垃圾回收信息
 *
 * 初始信息
 * StringTable statistics:
 * Number of buckets       :     60013 =    480104 bytes, avg   8.000
 * Number of entries       :      1711 =     41064 bytes, avg  24.000  //StirngTable中的key-value对 1711
 * Number of literals      :      1711 =    154040 bytes, avg  90.029  //字符串数量1711
 * 
 * 添加10000个字符串到StringTable后
 * StringTable statistics:
 * Number of buckets       :     60013 =    480104 bytes, avg   8.000
 * Number of entries       :      5845 =    140280 bytes, avg  24.000
 * Number of literals      :      5845 =    353352 bytes, avg  60.454
 * 数量小于11711,说明StringTable内进行了垃圾回收
 */
public class Demo6 {
    public static void main(String[] args) {
        int i = 0;
        try {
            for (int j = 0; j < 10000; j++) {
                String.valueOf(j).intern();
            }
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            System.out.println(i);
        }
    }
}
性能调优

StringTable采用的数据结构为哈希表,所以可以通过调整主数组的大小来减小哈希碰撞的概率,进而提升效率

  • 调整StringTable的桶大小
-XX:StringTableSize=桶个数
  • 考虑将字符串对象是否入池

如果程序运行期间会产生大量字符串,并且字符串重复数量较多,可以考虑将字符串进行入池操作,减少内存开销

入池前

在这里插入图片描述

入池后
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/836510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用大数据分析工具,实现多场景可视化数据管理

官方使用文档 https://yanhuang.yuque.com/staff-sbytbc/rb5rur? 准备服务器环境 购买服务器 购买腾讯云服务器&#xff0c;1300 元新人价&#xff0c;一年时间 ●4核16G内存 ●CentOS 6.7 &#xff08;补充说明&#xff1a;最新的 2.7.1 GA 版本&#xff0c;8G 内存也是可以…

TCP的三次握手四次挥手

TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手&#xff1a;为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 四次挥手&a…

flyway快速入门

flyway快速入门 一、flyway是什么&#xff1f;二、flyway使用目的1. 使用原因&#xff1a;2. 举个例子&#xff1a; 三、flyway工作原理四、flyway使用约定和命名规则1. 数据库版本文件整体约定2. 数据库版本文件夹管理约定3. 数据库版本文件命名约定4. 禁止项 五、flyway配置和…

微信多开(双开三开均可,且不局限于微信,其他设备亦可)

1.鼠标右键“微信”&#xff0c;属性 如上图&#xff0c;自动选取的&#xff0c;别动&#xff0c;然后CtrlC,,,,结果如下 "C:\Program Files (x86)\Tencent\WeChat\WeChat.exe" 2.创建文本&#xff0c;电脑桌面空白处单击&#xff0c;新建&#xff0c;文本档案&#…

Java版工程行业管理系统源码-专业的工程管理软件-em提供一站式服务 em

​ Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目…

安卓:BottomNavigationBar——底部导航栏控件

目录 一、BottomNavigationBar介绍 二、BottomNavigationBar的常用方法及其常用类 &#xff08;一&#xff09;、常用方法 1. 添加菜单项 2. 移除菜单项 3. 设置选中监听器 4. 设置当前选中项 5. 设置徽章 6. 样式和颜色定制 7. 动画效果 8. 隐藏底部导航栏。 9、设…

局域网新大陆?

操作后&#xff0c;即可实现局域网互通。

【java】民营医院、门诊部、连锁集团、公立医疗云HIS系统源码

基于云计算技术的B/S架构的医院管理系统(简称云HIS)&#xff0c;为医疗机构提供标准化的、信息化的、高效可靠的医疗信息管理系统&#xff0c;实现医患事务管理和临床诊疗管理等标准医疗管理信息系统的功能。利用云计算平台的技术优势&#xff0c;建立统一的云HIS、云病历、云P…

性能监控工具-Grafana安装和使用方法

Grafana是一款开源的数据可视化和监控平台。它提供了丰富的可视化方式&#xff0c;如图表、仪表盘、警报等&#xff0c;支持多种数据源&#xff0c;包括Prometheus、InfluxDB、Graphite等&#xff0c;适用于各种规模的系统监控和数据分析。Grafana还有一个强大的插件生态系统&a…

视频监控汇聚平台EasyCVR视频分享页面WebRTC流地址播放不了是什么原因?

开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多…

淘宝店铺数据API接口 店铺详情数据API 店铺所有商品API接口

引言 在电商平台上&#xff0c;店铺所有商品API接口是一项非常重要且有着广泛应用的技术。它使得开发者能够方便地获取和管理店铺中的所有商品信息&#xff0c;进而实现自动化的商品管理和数据分析。本文将详细介绍店铺所有商品API接口的定义、功能以及调用流程&#xff0c;并附…

王道《操作系统》学习(二)——进程管理(三)

2.3.1 进程同步、进程互斥 &#xff08;1&#xff09;进程同步 &#xff08;2&#xff09;进程互斥 “同时”指的是宏观上的同时&#xff0c;微观上可能这些进程是交替地在访问这些共享资源的 当“上锁”后&#xff0c;其他的进程想要访问临界资源时&#xff0c;在进入区进行检…

js修改png图片颜色

思路是利用canvas 改变图片颜色 /*** 将png图片转成目标颜色* param imgUrl 可传入图片URL 或者 Base64* param RGBArr 要换成的目标颜色RGB 数组格式[R,G,B]* param Functon callback回调*/ function changeImageColor(imgUrl, RGBArr, callback) {let image new Image();im…

人工智能大模型中token的理解

“token”是当前语言类模型的数据单位。当前的自回归语言模型是根据 token 来作为单位进行数据处理和计算&#xff0c;分词&#xff08;tokenization&#xff09;就是将句子、段落、文章这类型的长文本分解为以 token 为单位的数据结构&#xff0c;把文本分词后每个词表示成向量…

小白入门Java第一天

当你对 Java语言有了一些了解后&#xff0c;你就可以开始着手学习Java了。 作为你的Java 学习第一天&#xff0c;所需掌握内容如下述目录&#xff1a; 文章目录 1. 注释1. 三种注释1.1 单行注释1.2 多行注释1.3 文档注释 2. 标识符和关键字2.1 标识符的组成&#xff1a;2.2 那…

C++11新特性lambda 表达式

lambda 表达式 lambda 表达式 lambda 表达式 Lambda 表达式的基本语法是&#xff1a;[] (参数列表) -> 返回值类型 {函数体}。 方括号([])表示捕获列表&#xff0c;用来指定在 lambda 表达式中可以访问的外部变量。 参数列表和返回值类型与普通函数的参数列表和返回值类型相…

写字楼门禁如何管理?最最新方法来了!

在现代社会&#xff0c;随着城市化和商务发展的蓬勃推进&#xff0c;大厦写字楼作为繁忙的商业中心和办公场所&#xff0c;其安全管理和员工考勤变得尤为重要。为了应对这一挑战&#xff0c;人脸门禁考勤机应运而生&#xff0c;成为大厦写字楼的安全保障和工时管理的关键工具。…

翻译公司提供哪些口译服务,北京翻译哪里比较专业?

我们知道&#xff0c;口译服务是一种即席的现场翻译活动&#xff0c;在涉外沟通交流中起着至关重要的作用。那么&#xff0c;如何做好口译工作&#xff0c;翻译公司提供哪些口译服务&#xff0c;北京翻译哪里比较专业&#xff1f; 据了解&#xff0c;相对于笔译&#xff0c;口译…

《吐血整理》高级系列教程-吃透Fiddler抓包教程(27)-Fiddler如何抓取Android7.0以上的Https包-中篇

1.简介 上一篇中&#xff0c;讲解和分享了一些如何快速解决的临时应急的的方法&#xff0c;但是小伙伴或者童鞋们是不是觉得是一些头痛医头脚痛医脚的方法&#xff0c;治标不治本&#xff0c;或者是一些对于测试人员实现起来比较有一定难度。所以今天宏哥再介绍和分享一下治本…

长相思·罚站墙Vue

优化前 看效果图 Vue长相思 刚学Vue&#xff0c;正好在追剧&#xff0c;看到这个小案例觉得挺好玩的&#xff0c;第一天学&#xff0c;代码太简陋了 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta…