JVM字符串常量池StringTable

目录

一、StringTable为什么要调整

二、String的基本特性

三、String的内存分配

四、字符串拼接操作

五、intern()方法

六、Stringtable的垃圾回收

七、G1中String去重操作


一、StringTable为什么要调整

jdk7之前,hotspot对于方法区的实现是永久代,常量池包括字符串常量池放于永久代中;

jdk7时,hotspot将字符串常量池(还有静态变量)放在了堆中。有一点“去永久代”的苗头

jdk8之后,hotspot取出永久代,取而代之的是使用本地内存的元空间。字符串常量池还是在堆中。

为什么要将字符串常量池StringTable放在堆中?

jdk7中将StringTable放到了堆空间中,因为永久代的回收效率很低。在fullGC的时候才触发,而fullGC是老年代空间不足,永久代不足时才触发,触发次数较少,甚至在开发中我们要避免出现fullGC。这就导致了StringTable回收效率不高,而我们开发中会创建大量的字符串,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。

二、String的基本特性

jdk8及以前,内部定义了final char[] value用于存储字符串数据

JDK9时改为byte[] + 字符类型标记,为什么做出这个改变呢?

char数组一个char占16bits(两个字节),String是堆空间的主要部分,大部分是latin-1字符,一个字节就够了,这样会有一半空间浪费。所以采用byte数组+字符串类型,如果是中文等UTF-16 的用两个字节存储。

StringBuffer,StringBuilder同样做了修改

String为什么不可变?

因为底层数组被final修饰。而且其类自身也被final修饰,这就导致了不能通过继承去修改其内部结构。保证了其不可变性。

  • 当字符串重新赋值,需要重写指定内存区域赋值,不能使用原有的value进行赋值
  • 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能对使用原有的value进行赋值
  • 当调用String的replace方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

字符串常量池中不会存储相同的字符串的

String的String pool是一个固定大小的HashTable,默认大小长度是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了,直接影响就是调用String.intern时性能会大幅下降

  • -XX:StringTableSize可设置StringTable的大小
  • JDK6固定1009,jdk7中StringTable默认的长度是60013,JDK8时默认是60013,1009是可设置的最小值

三、String的内存分配

Java语言中有8种基本数据类型和一种比较特殊的类型String,这些类型为了使他们再运行过程中速度更快,更节省内存,都提供了一种常量池的概念

String的常量池比较特殊,主要使用方法有两种

  • 直接使用双引号,声明出来的String对象会直接存储在常量池中
  • 如果不是双引号声明的String对象,可以使用String提供的intern()方法

jdk6及之前,字符串常量池存在永久代

jdk7中,字符串常量池调整到Java堆中,调优时仅需调整堆大小就可以

四、字符串拼接操作

常量与常量的拼接结果在常量池,原理是编译期优化

只要其中有一个变量,拼接结果就在堆中(常量池以外的堆),变量的拼接原理是StringBuilder 

String res  = s1 + s2; 
// 实际上是StringBuilder s = new StringBuilder().append(s1).append(s2); 
// 然后调用s.toString();

 

如果拼接的结果调用intern方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址

字符串拼接操作不一定使用的是StringBuilder如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式

针对final修饰类,方法,基本数据类型,引用数据类型变量的结构时,能使用final尽量使用上

 

五、intern()方法

jdk1.6中,将这个字符串对象放入串池

  • 如果串池中有,则并不会放入,返回已有串池中的对象的地址,
  • 如果没有,会把对象复制一份,放入串池,并返回串池中的对象地址

jdk1.7起,将这个字符串对象尝试放入串池

  • 如果串池中有,则并不会放入,返回已有的串池中的对象的地址
  • 如果没有,则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址

例子:

前置知识

newString("ab")会创建几个对象?

2个对象,查看字节码验证。一个是常量池ab,一个是new出来在堆空间。(前提是常量池没有ab)

new String("a")+new String("b")?

  • 对象1,有拼接操作就newStringBuilder
  • 对象2,new一个String
  • 对象3,常量池a
  • 对象4,new String
  • 对象5,常量池b
  • 对象6,StringBuilder,toString方法会new String返回
    • 注意:toString方法这里new String并不会向字符串常量池中放入"ab",不像我们平时上面一样会放入一个“ab”在常量池中。

结果

jdk6        false false

jdk7/8        false true

分析:

jdk6的intern会复制一份"1"放入字符串常量池。但是new的时候其实已经放入常量池了,所以这里intern没啥用,此时s2拿到的就是常量池的那一份。而s是指向堆中new出来的String对象,所以为false

s3这里intern的时候常量池没有“11”,所以会复制一份放入常量池,此时s4拿到的就是常量池的那一份。而s3指向堆中new出来的String对象,所以为false

jdk7/8的intern是复制引用地址放入字符串常量池,但是new的时候其实已经放入常量池了,所以这里intern没啥用,此时s2拿到的就是常量池的那一份。所以为false

s3这里intern的时候常量池没有“11”,所以会复制引用放入常量池,此时s4拿到的就是常量池的那一份引用。而s3也指向堆中new出来的String对象,所以为true

六、Stringtable的垃圾回收

-XX:+PrintStringTableStatistics

七、G1中String去重操作

背景:对许多Java应用,做的测试结果如下

  • 堆存货数据集合里面String对象占了25%
  • 堆存活数据集合里面重复的String对象有13.5%
  • String对象的平均长度是45

许多大规模的Java应用的瓶颈在于内存。Java堆中存活的数据集合差不多25%是String对象,这里差不多一半的String对象是重复的, 重复是指equals方法=true,堆上重复的String对象必然是一种内存的浪费。G1垃圾收集器中实现自动持续对重复的String对象进行去重,这样避免浪费。

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

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

相关文章

【图像处理:OpenCV-Python基础操作】

【图像处理:OpenCV-Python基础操作】 1 读取图像2 显示图像3 保存图像4 图像二值化、灰度图、彩色图,像素替换5 通道处理(通道拆分、合并)6 调整尺寸大小7 提取感兴趣区域、掩膜8 乘法、逻辑运算9 HSV色彩空间,获取特定…

ENVI IDL:如何基于气象站点数据进行反距离权重插值?

01 前言 仅仅练习,大可使用ArcGIS或者已经封装好的python模块进行插值,此处仅仅从底层理解如何从公式和代码理解反距离权重插值的过程,从而更深刻的理解IDL的使用和插值的理解。 02 函数说明 2.1 Read_CSV()函数 官方语法如下&#xff1a…

Python---字典---dict

1、为什么需要字典 如果想要存储一个人的信息,姓名:Tom,年龄:20周岁,性别:男,如何快速存储。 person [Tom, 20, 男] 在日常生活中,姓名、年龄以及性别同属于一个人的基本特征。 但…

Please No More Sigma(构造矩阵)

Please No More Sigma 给f(n)定义如下&#xff1a; f(n)1 n1,2; f(n)f(n-1)f(n-2) n>2; 给定n&#xff0c;求下式模1e97后的值 Input 第一行一个数字T&#xff0c;表示样例数 以下有T行&#xff0c;每行一个数&#xff0c;表示n。 保证T<100&#xff0c;n<100000…

51单片机入门

一、单片机以及开发板介绍 写在前面&#xff1a;本文为作者自学笔记&#xff0c;课程为哔哩哔哩江协科技51单片机入门教程&#xff0c;感兴趣可以看看&#xff0c;适合普中A2开发板或者HC6800-ESV2.0江协科技课程所用开发板。 工具安装请另行搜索&#xff0c;这里不做介绍&…

CompareM-平均氨基酸一致性(AAI)计算

文章目录 Comparem简介比较基因组统计基因组使用模式其他 安装使用基于基因组计算氨基酸一致性基于基因组蛋白计算氨基酸一致性 结果转变成矩阵参考 Comparem简介 CompareM 是一个支持进行大规模基因组比较分析的软件工具包。它提供跨基因组&#xff08;如氨基酸一致性&#x…

《未来之路:技术探索与梦想的追逐》

创作纪念日 日期&#xff1a;2023年07月05日文章标题&#xff1a;《从零开始-与大语言模型对话学技术-gradio篇&#xff08;1&#xff09;》成为创作者第128天 在这个平凡的一天&#xff0c;我撰写了自己的第一篇技术博客&#xff0c;题为《从零开始-与大语言模型对话学技术-…

深度学习的集体智慧:最新发展综述

一、说明 我们调查了来自复杂系统的想法&#xff0c;如群体智能、自组织和紧急行为&#xff0c;这些想法在机器学习中越来越受欢迎。人工神经网络正在影响我们的日常生活&#xff0c;从执行预测性任务&#xff08;如推荐、面部识别和对象分类&#xff09;到生成任务&#xff08…

RT-DETR算法改进:更换损失函数DIoU损失函数,提升RT-DETR检测精度

💡本篇内容:RT-DETR算法改进:更换损失函数DIoU损失函数 💡本博客 改进源代码改进 适用于 RT-DETR目标检测算法(ultralytics项目版本) 按步骤操作运行改进后的代码即可🚀🚀🚀 💡改进 RT-DETR 目标检测算法专属 文章目录 一、DIoU理论部分 + 最新 RT-DETR算法…

从0到0.01入门React | 008.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

自动计算零售数据分析指标?BI软件表示可行

随着BI技术的飞速发展&#xff0c;借助系统来计算分析指标也不是什么难事&#xff0c;即便是面对组合多变的零售数据分析指标&#xff0c;奥威BI软件也依旧可以又快又精准地完成指标计算。 BI软件可以自动计算零售数据分析指标&#xff0c;如销售额、库存量、订单量等。在计算…

[工业自动化-11]:西门子S7-15xxx编程 - PLC从站 - 分布式IO从站/从机

目录 一、什么是以分布式IO从站/从机 二、分布式IO从站的意义 三、ET200分布式从站系列 一、什么是以分布式IO从站/从机 在工业自动化领域中&#xff0c;分布式 IO 系统是目前应用最为广泛的一种 I/O 系统&#xff0c;其中分布式 IO 从站是一个重要的组成部分。 分布式 IO …

Redis系列-四种部署方式-单机部署+主从模式+哨兵模式【7】

目录 Redis系列-四种部署方式-单机部署主从模式【7】redis-四种部署模式单机模式主从模式数据同步的方式全量数据同步增量数据同步 Redis哨兵模式总结缺点&#xff1a;哨兵模式应用sentinel.conf配置项 REF 个人主页: 【⭐️个人主页】 需要您的【&#x1f496; 点赞关注】支持…

移动医疗科技:开发互联网医院系统源码

在这个数字化时代&#xff0c;互联网医院系统成为了提供便捷、高效医疗服务的重要手段。本文将介绍利用移动医疗科技开发互联网医院系统的源码&#xff0c;为医疗行业的数字化转型提供有力支持。 智慧医疗、互联网医院这一类平台可以通过线上的形式进行部分医疗服务&#xff…

59基于matlab的爬行动物搜索算法(Reptile search algorithm, RSA)

基于matlab的爬行动物搜索算法&#xff08;Reptile search algorithm, RSA&#xff09;一种新型智能优化算法。该算法主要模拟鳄鱼的捕食行为&#xff0c;来实现寻优求解&#xff0c;具有收敛速度快&#xff0c;寻优能力强的特点。程序已调通&#xff0c;可直接运行。 59matlab…

云原生微服务架构及实现技术

云原生是一种技术理念和架构方法&#xff0c;它充分利用云计算的优势&#xff0c;将应用程序和基础设施进行优化&#xff0c;以适应云环境的特性。云原生的设计原则主要包括弹性、韧性、安全性、可观测性、灰度等&#xff0c;旨在让企业在云环境中实现轻量、敏捷、高度自动化的…

从0开始python学习-33.夹具@pytest.fixture(scope=““,params=““,autouse=““,ids=““,name=““)

目录 1. 创建夹具 1.1 pytest方式 1.2 unittest方式 2. 使用夹具 2.1 通过参数引用 2.2 通过函数引用 3. 参数详解 3.1 scope&#xff1a;作用域 3.2 params-参数化 3.3 autouseTrue表示自动使用&#xff0c;默认为False 3.4 ids&#xff1a;设置变量名 3.5 name&am…

[ARM入门]ARM模式及其切换、异常

ARM技术特征 ARM处理器有如下特点 体积小、功耗低、成本低、性能高支持Thumb&#xff08;16位&#xff09;/ARM&#xff08;32位&#xff09;双指令集&#xff0c;能很好地兼容8位/16位器件大量使用寄存器&#xff0c;指令执行速度更快大多数数据操作都在寄存器中完成寻址方式…

Java中的7大设计原则

在面向对象的设计过程中&#xff0c;首先需要考虑的是如何同时提高一个软件系统的可维护性和可复用性。这时&#xff0c;遵从面向对象的设计原则&#xff0c;可以在进行设计方案时减少错误设计的产生&#xff0c;从不同的角度提升一个软件结构的设计水平。 1、单一职责 一个类…

【Redis】set 集合

上一篇&#xff1a;list 列表 https://blog.csdn.net/m0_67930426/article/details/134364315?spm1001.2014.3001.5501 目录 Sadd Smembers Sismember Scard Srem ​编辑Srandomember Spop Smove 集合类 Sdiff Sinter Sunion 官网 https://redis.io/commands/?…