JVM 补充——StringTable

news/发布时间2024/9/20 5:48:13

具体哪些String是相等的,各种String的情况,看这个:

https://javaguide.cn/java/basis/java-basic-questions-02.html#string-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF%E4%B8%8D%E5%8F%AF%E5%8F%98%E7%9A%84

String的基本特性

  • String:字符串,使用一对“”引起来表示
    • 声明方式和基础类型类似:String str = “abc”;
    • 也可以:String str = new String(“hello”);
  • String声明为final的,不可被继承
  • String实现了Serializable接口:表示字符串是支持序列化的
    • 实现了Comparable接口:表示String可以比较大小
  • String 在Java8时,内部使用final char[] value来存储字符串数据。Java9改成了byte[]加编码标记哪种正在使用哪种字符编码,节省了一些空间
    • 原因是设计者们发现String里面大部分是拉丁字符,而拉丁字符只占一个字节,浪费了一半的空间
    • 和String有关的类,比如StringBuilder,StringBuffer都做出了相应的改变
  • String的不可变性
    • 当对字符串重新赋值时,会新建一个字面量,然后把新的字面量的地址赋值给String变量
    • 当对现有的字符串进行连接操作时,也是创建新对象,,,
    • 当调用String的replace方法修改指定字符或字符串时,也是返回一个新对象,,,
  • 字符串常量
    • 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
    • 字符串常量池是不会存储相同内存的字符串的【Java语言规范里要求完全相同的字符串字面量应该包含同样的Unicode字符序列(包含同一份码点序列的常量),并且必须是指向同一个String类实例】
    • 字符串常量池是一个固定大小的HashTable(数组+链表),默认大小长度为1009。如果放进常量池的String非常多,就会造成Hash冲突严重,导致链表会很长,链表长了之后调用String.intern时的性能会大幅下降
    • -XX:StringTableSize 可设置StringTable的长度
    • jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTableSize设置没有要求
    • jdk7中StringTable的长度默认值是60013
    • jdk8中默认值一样,但是设置StringTable的长度时,1009是可设置的最小值

String的内存分配

  • 在Java语言中有8种基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念
  • 常量池就类似一个Java系统级别提供的缓存。8种基本数据类型的常量池都是系统协调的。String的常量池比较特殊。它的主要使用方法有两种
    • 直接使用双引号声明出来的String对象会直接储存在常量池中
      • 比如 String info = “atguigu.com”;
    • 如果不是用双引号声明的String对象,可以使用String提供的intern()方法
  • 变化
    • Java 6及以前,字符串常量池存放在永久代
    • Java 7中Oracle的工程师对字符串池的逻辑做了很大的改变,即将字符串常量池的位置调整到Java堆中
      • 所有的字符串都保存在堆中,和其他普通对象一样,这样可以让你在进行调优应用使仅需要调整堆大小就可以了
      • 字符串常量池原先使用得比较少(因为怕永久代的OOM),现在常量池放进堆里面,就可以重新考虑在Java 7中使用String.intern
    • Java 8元空间,字符串常量仍然在堆中
    • 为什么字符串常量池要移入堆中?
      • 1.因为永久代比较小,字符串一多就容易OOM
      • 2.永久代很少GC,大量的空间被占用,不能及时清理

字符串拼接操作

  • 1.常量与常量的拼接结果在常量池,原理是编译期优化
  • 2.常量池中不会存在相同内容的常量
  • 3.只要其中有一个是变量【注意是变量,加了final就是常量引用,是常量相加,不是变量相��】,则相当于在堆中new String() (新建了一个对象),它的值为拼接的结果。变量的拼接原理是StringBuilder
    • 所以,类,方法,变量等,能用final修饰的尽量用
  • 4.如果拼接的结果调用intern()方法,如果常量池没有和这个拼接结果一样的字符串,常量池就新建个对象,并返回此对象地址。如果有了就直接返回那个字符串的地址
    • 拼接之后不调用 intern()方法 常量池是没有这个对象的
  • 请添加图片描述
  • 请添加图片描述
  • 使用StringBuilder拼接字符串比直接拼接字符串好
    • 1.使用StringBuilder拼接比直接拼接快很多倍。直接拼接,会创建过多的StringBuilder和String对象。而使用StringBuilder拼接,自始至终只产生一个StringBuilder对象
    • 2.直接拼接,创建过多对象,给GC带来压力
    • 改进:如果确定拼接之后的字符串长度不会超过某个最大值,可以用StringBuilder构造器指定大小,防止StringBuilder频繁扩容
      • StringBuilder s = new StringBuilder(high level);

intern()的使用

  • 如果不是用双引号声明的String对象,可以使用String提供的intern方法:intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。
    • 比如:String myInfo = new String(“I love atguigu”).intern();
  • 也就是说,如果在任意字符串上调用String.intern方法,其返回结果指向的那个类实例,必须和直接以常量形式出现的字符串实例完全相同。因此,下列表达式的值必定为true:
    • (“a”+“b”+“c”).intern() == “abc”
  • 通俗点讲,Interned String 就是确保字符串在内存中只有一份拷贝,这样可以节约内存空间,加快字符串操作任务的执行速度。注意,这个值会被存放在字符串内部池(String Intern Pool)

请添加图片描述

  • new String(“a”) 会产生几个对象?2个

    • 一个是new 的 String对象
    • 一个是在常量池产生的常量 “a”(前提是常量池之前没有"a")
  • new String(“a”) + new String(“b”)会产生几个对象? 6个

    • 一个是StringBuilder因为是变量和变量相加,不是常量+常量
    • 一个是 new 的String
    • 一个是在常量池产生的常量"a"
    • 一个是new 的String
    • 一个是在常量池产生的常量"b"
    • 还有一个!StringBuilder最后还会调用toString()方法,toString方法会new 一个String()对象。
      • 但是!!!在字节码文件看toString的指令,里面没有在常量池创建常量,就是这里的代码,常量池不会多一个"ab"
  • 一个很难的面试题

    • Java7中,将常量池放入了堆中。为了节省空间,它在常量池里不是新建一个常量"11",而是新建一个指针 指向"11",所以s3和s4一样
      • 而在其他情况下,一般都是直接赋值 “”比如 String s = “11”,或者 String s = new String(“11”) 这两个过程都是会在常量池里生成常量的
      • String s3 = new String(“1”) +new String(“1”) 这种生成了String对象,但是没有在常量池里生成常量的情况,真的很特殊
      • **也只有在这种情况下使用 s3.intern()方法会使用 现有String的对象,而不是自己创建一个【其他情况调用****intern()**还是会直接新建常量的】
    • 请添加图片描述
    • 拓展
    • 请添加图片描述
    • 总结String的intern()方法的使用:
      • jdk1.6中,将这个字符串对象尝试放入常量池
        • 如果常量池有,则不会放入。返回已有的常量池中的对象的地址
        • 如果没有,就会将此对象复制一份(就是新建一个值一样的对象),放入常量池,并返回常量池中的对象地址
      • jdk1.7中,将这个字符串对象尝试放入常量池
        • 如果常量池有,则不会放入。返回已有的常量池中的对象的地址
        • 如果没有,则会把对象的引用地址复制一份,放入常量池,并返回常量池中的引用地址
    • 当有大量字符串循环赋值的时候,使用intern()可以大大节省空间和加快速度
      • 请添加图片描述
        请添加图片描述
        G1对堆中String对象的去重(常量池都是唯一的,不用去重)
  • 请添加图片描述

  • 请添加图片描述

  • 感觉应该挺好用,不知道为什么不默认开启

  • 请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

最佳实践:Websocket 长连接状态如何保持

WebSocket 是一种支持通过单个 TCP 连接进行全双工通信的协议,相较于传统的 HTTP 协议,它更适合需要实时交互的应用场景。此协议在现代 Web 应用中扮演着至关重要的角色,尤其是在需要实时更新和通信的场合下维持持久连接。本文将探讨 WebSock…

Harbor高可用(haproxy和keepalived)

Harbor高可用(haproxy和keepalived) 文章目录 Harbor高可用(haproxy和keepalived)1.Harbor高可用集群部署架构1.1 主机初始化1.1.1 设置网卡名和ip地址1.1.2 设置主机名1.1.3 配置镜像源1.1.4 关闭防火墙1.1.5 禁用SELinux1.1.6 设…

MySQL 存储过程批量插入总结

功能需求背景:今天接到产品经理核心业务表的数据压测功能,让我向核心业务表插入百万级的业务量数据,我首先想到的办法就是存储过程实现数据的批量 。 由于无法提供核心业务表,本文仅仅提供我刚刚自己创建的表bds_base_user 表做相…

Python爬虫实战第二例【二】

零.前言: 本文章借鉴:Python爬虫实战(五):根据关键字爬取某度图片批量下载到本地(附上完整源码)_python爬虫下载图片-CSDN博客 大佬的文章里面有API的获取,在这里我就不赘述了。 一…

化肥工业5G智能制造工厂数字孪生可视化平台,推进化肥行业数字化转型

化肥工业5G智能制造工厂数字孪生可视化平台,推进化肥行业数字化转型。随着科技的不断发展,数字化转型已经成为各行各业发展的必然趋势。在化肥工业领域,5G智能制造工厂数字孪生可视化平台的应用正在逐渐普及,为行业数字化转型提供…

我用 Go 开发了一个简易版 shell

之前看到 Github 有个 build-your-own-x 的仓库,觉得挺有意思的,有不少有趣的实现。我就想着多尝试实现些这样的小项目,看看不同的领域。一方面提升我的编程能力,另外,也希望能发现一些不错的项目。 今天的项目在 bui…

IK分词器的入门使用

目录 1. 前言2. IK分词器的特点3. 引入IK分词器的依赖4. 示例代码5.结论 1. 前言 中文分词是将连续的中文文本切分成一个个独立的词语的过程,是中文文本处理的基础。IK分词器是一个高效准确的中文分词工具,采用了"正向最大匹配"算法&#xff…

命令行启动mongodb服务器的问题及解决方案 -- Unrecognized option: storage.journal

目录 mongodb命令行启动问题 -- Unrecognized option: storage.journal问题日志:问题截图:问题来源:错误原因:解决方式: mongodb命令行启动问题 – Unrecognized option: storage.journal 同样是格式出问题的问题分析和…

tomcat基础介绍

目录 一、Tomcat的基本介绍 1、Tomcat是什么? 2、Tomcat的配置文件详解 3、Tomcat的构成组件 6、Tomcat的请求过程 一、Tomcat的基本介绍 1、Tomcat是什么? Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器…

Slurm作业系统

1、什么是计算机集群 计算机集群是由多台独立的计算机(节点)通过网络连接在一起,以共同完成任务的一种计算机系统结构。集群系统旨在提高性能、可用性和可扩展性。以下是计算机集群的一般结构和组成要素: 节点(Nodes&…

rust学习(tokio协程分析一)

代码: async fn doAsyncPrint(v:u32) {println!("start doAsyncPrint,v is {},tid is {:?}",v,system::myTid());//thread::sleep(Duration::from_secs(1));time::sleep(Duration::from_secs(10)).await;println!("end,v is {},tid is {:?}"…

使用正则表达式的SqlServer Check约束实例

有表如下;会员表,第一个字段是会员编号,varchar(24)类型;第二个字段是单位名称; 现在插入一条记录,会员编号为abcd;插入了; 下面要添加一个约束,会员编号字段只能为数字的…

适配器模式 详解 设计模式

适配器模式 适配器模式是一种结构型设计模式,其主要作用是解决两个不兼容接口之间的兼容性问题。适配器模式通过引入一个适配器来将一个类的接口转换成客户端所期望的另一个接口,从而让原本由于接口不匹配而无法协同工作的类能够协同工作。 结构 适配…

【自然语言处理】NLP入门(一):1、正则表达式与Python中的实现(1):字符串构造、字符串截取

文章目录 一、前言二、正则表达式与Python中的实现1. 字符串构造a. 使用str函数b. 单引号或双引号构造字符串c. 单双引号构造字符串的特殊用法d. 三重引号字符串e. 典例 2. 字符串截取a. 索引b. 切片c. 注意事项 一、前言 语言是一种使用具有共同处理规则的沟通指令的广义概念&…

用html编写的小广告板

用html编写的小广告板 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</tit…

类加载的基本流程

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;JavaEE &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 类加载 1. 加载2. 验证3. 准备4. 解析5. 初…

AI大预言模型——ChatGPT与AI绘图及论文高效写作

原文链接&#xff1a;AI大预言模型——ChatGPT与AI绘图及论文高效写作 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网…

JVM运行时数据区——虚拟机栈

文章目录 1、虚拟机栈概述1.1、StackOverflowError1.2、OOM异常 2、栈的存储单位3、局部变量表3.1、局部变量表简介3.2、Slot 4、操作数栈5、栈顶缓存技术6、动态链接7、方法的调用7.1、方法调用的分类7.2、虚方法与非虚方法7.3、关于invokedynamic指令7.4、方法重写的本质7.5、…

【Django】执行查询—跨关系查询中的跨多值关联问题

跨多值查询 跨越 ManyToManyField 或反查 ForeignKey &#xff08;例如从 Blog 到 Entry &#xff09;时&#xff0c;对多个属性进行过滤会产生这样的问题&#xff1a;是否要求每个属性都在同一个相关对象中重合。 filter() 先看filter()&#xff0c;通过一个例子看&#xf…

C语言 vs Rust应该学习哪个?

C语言 vs Rust应该学习哪个&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&am…
推荐文章