Java --- JVM之StringTable

目录

一、String的基本特性

 二、String的内存分配

2.1、String内存分布图

三、字符串拼接操作 

 3.1、字符串拼接操作底层原理

3.2、拼接操作与append操作效率对比 

四、intern()方法 

4.1、intern()效率

五、StringTable的垃圾回收

一、String的基本特性

1、String字符串,使用一对""引起表示

2、String声明为Final的,不可被继承

3、String实现了Serializable接口:表示字符串是支持序列化的。实现Comparable接口:表示String可以比较大小。

4、String字符串在JDK8及以前内部定义了final char[] value用于存储字符串数据。jdk9时改为byte[]。

5、String代表不可变的字符串序列。①、当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。②、当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。③、当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

6、通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。

参考代码:

public class StringTest {@Testpublic void test1(){String s1 = "a";String s2 = "a";s2 = "b";System.out.println(s1 == s2);//falseSystem.out.println(s1);//aSystem.out.println(s2);//b}@Testpublic void test2(){String s1 = "a";String s2 = "a";s2 += "b";System.out.println(s1);//aSystem.out.println(s2);//ab}@Testpublic void test3(){String s1 = "a";String s2 = s1.replace('a','b');System.out.println(s1);//aSystem.out.println(s2);//b}
}

面试题:

public class StringTest02 {String s1 = new String("hello");char[] chars = {'t','o','m'};public void change(String s1,char chars[]){s1 = "test ok";chars[0] = 'a';}public static void main(String[] args) {StringTest02 str = new StringTest02();str.change(str.s1,str.chars);System.out.println(str.s1);//”hello“System.out.println(str.chars);//”aom“}
}

 7、字符串常量池是不会存储相同内容的字符串。

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

参考代码:

public class StringTest04 {public static void main(String[] args) {try {FileWriter fileWriter = new FileWriter("hello.txt");for (int i = 0; i < 100000; i++) {int length = (int) (Math.random() * (10) + 1);fileWriter.write(getString(length) + "\n");}fileWriter.close();} catch (IOException e) {throw new RuntimeException(e);}}public static String getString(int length){String str = "";for (int i = 0; i < length; i++) {int num = (int) (Math.random() * (90 - 65 + 1) + 65) + (int) (Math.random() * 2) * 32;str += (char)num;}return str;}
}
public class StringTest03 {public static void main(String[] args)  {//参数设置:-XX:StringTableSize=1009
//        System.out.println("String参数设置开始");
//        try {
//            Thread.sleep(100000);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }BufferedReader bufferedReader = null;try {bufferedReader = new BufferedReader(new FileReader("hello.txt"));long start = System.currentTimeMillis();String data;while ((data = bufferedReader.readLine()) != null){data.intern();}long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end - start));//参数1009.时间91ms。参数1000009,时间35ms} catch (IOException e) {throw new RuntimeException(e);}finally {if (bufferedReader != null){try {bufferedReader.close();} catch (IOException e) {throw new RuntimeException(e);}}}}}

②、使用-XX:StringTableSize可设置StringTable的长度。

③、在jdk6中的StringTable的是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTableSize设置没有要求。

④、在jdk7中,StringTable的默认长度是60013,jdk8及以后1009是设置的最小值。

以jdk8测试:

 二、String的内存分配

1、Java语言中有八大基本数据类型和特殊的String类型,这些类型为了使它们在运行过程中速度更快,更节省内存,都提供了一种常量池概念。

2、常量池类似一个Java系统级别提供缓存。8种基本数据类型的常量池都是系统协调的,String类型的常量池比较特殊。

      ①、直接使用双引号声明出来的String对象会直接存储在常量池中。

      ②、不使用双引号声明的String对象,可以使用String提供的intern()方法。

3、Java6及以前,字符串常量池存放在永久代中。

4、Java7中将字符串常量池的位置调整到Java堆中

     ①、所有的字符串都保存在堆中,和其他普通对象一样,这样可以在进行调优应用时仅需要调整堆大小就可以了。

     ②、字符串常量池概念原本使用的比较多,但改动后可以重新考虑在Java7中使用String.intern()

5、Java8元空间,字符串常量在堆。

2.1、String内存分布图

三、字符串拼接操作 

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

2、常量池中不会存在相同内容的常量。

3、只要其中一个是变量,结果就在堆中。变量的拼接的原理是StringBuilder。

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

参考代码:

 @Testpublic void test1(){String s1 = "a" + "b" + "c";String s2 = "abc";System.out.println(s1 == s2);//trueSystem.out.println(s1.equals(s2));//true}@Testpublic void test2(){String s1 = "javaee";String s2 = "hadoop";String s3 = "javaeehadoop";String s4 = "javaee" + "hadoop";//编译期优化//拼接字符串的前后出现变量,相当于在堆空间中new String(),String s5 = s1 + "hadoop";String s6 = "javaee" + s2;String s7 = s1 + s2;System.out.println(s3 == s4);//trueSystem.out.println(s3 == s5);//falseSystem.out.println(s3 == s6);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s5 == s6);//falseSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//false//intern(),判断字符串常量池中是否存在javaeehadoop值,有就返回该值地址,没有就重新加载一份。String s8 = s6.intern();System.out.println(s3 == s8);//true}

 3.1、字符串拼接操作底层原理

参考代码:

 @Testpublic void test3(){String s1 = "a";String s2 = "b";String s3 = "ab";/*** s1 + s2执行步骤* ①、StringBuilder s = new StringBuilder();* ②、s.append("a")* ③、s.append("b")* s.toString() ---> 约等于 new String("ab");*/String s4 = s1 + s2;System.out.println(s3 == s4);//false}@Testpublic void test4(){/*** 字符串拼接操作不一定使用StringBuilder()* 如拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化* 针对于final修饰的类、方法、基本数据类型,引用数据类型的量的结构时,能使用final时建议使用*/final String s1 = "a";final String s2 = "b";String s3 = "ab";String s4 = s1 + s2;System.out.println(s3 == s4);//true}

3.2、拼接操作与append操作效率对比 

参考代码:

@Testpublic void test5(){/***通过StringBuilder的append()的方式添加字符串的效率要远高于字符串拼接* ①、StringBuilder的append()方式,只需要创建一个StringBuilder对象,而字符串拼接则需要创建多个StringBuilder和String对象* ②、使用String的字符串拼接方式,内存中创建了较多的StringBuilder和String对象,内存占用更大,如垃圾回收效率要更频繁* 优化:在基本确定要添加的字符串的长度不高于某个限定值highlevel,可以使用构造器new StringBuilder(参数)*/long start = System.currentTimeMillis();method1(10000);long end = System.currentTimeMillis();System.out.println("method1花费时间为:" + (end - start));//89long start1 = System.currentTimeMillis();method2(10000);long end1 = System.currentTimeMillis();System.out.println("method2花费时间为:" + (end1 - start1));//0}public void method1(int highLevel){String str = "";for (int i = 0; i < highLevel; i++) {str = str + "a";}}public void method2(int highLevel){StringBuilder stringBuilder = new StringBuilder();for (int i = 0; i < highLevel; i++) {stringBuilder = stringBuilder.append("a");}}

四、intern()方法 

如果不是双引号声明的String对象,可以使用String提供的intern():intern方法会从字符串常量池中查询当前字符串是否存在,如不存在就会将当前字符串放入常量池中。

public class StringTest07 {//以jdk8为例public static void main(String[] args) {String s = new String("1");s.intern();//调用此方法之前,常量池中已经有“1"String s1 = "1";System.out.println(s == s1);//false//s3变量的记录地址为new String(”11“),但在常量池中没有创建的”11“String  s3 = new String("1") + new String("1");s3.intern();//该方法执行完就生成11,但没有在常量池中创建”11“,而是创建一个指向堆空间中new String(”11“)的地址String s4 = "11";//使用的是上行代码生成的”11“ --》即常量池中生成的”11“的地址System.out.println(s3 == s4);//true}
}

 总结:在jdk6中,如果串池中有,就返回已有的串池中的对象的地址,如果没有,就是将这个对象复制一份,放入串池,并返回这个对象的地址。从jdk7起,如果串池中有,就返回已有的串池中的对象的地址,如果没有,就是将这个对象的引用地址复制一份,放入串池,并返回串池中的引用地址。

4.1、intern()效率

参考代码:

public class StringTest08 {static final int MAX_COUNT = 1000 * 10000;static final String[] arr = new String[MAX_COUNT];public static void main(String[] args) {int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9};long start = System.currentTimeMillis();for (int i = 0; i < MAX_COUNT; i++) {//arr[i] = new String(String.valueOf(data[i % data.length]));arr[i] = new String(String.valueOf(data[i % data.length])).intern();}long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end - start));try {Thread.sleep(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.gc();}
}

 结论:对于程序中大量存在的字符串,尤其其中存在很多重复字符串时,使用intern()可以节省很多内存空间。

五、StringTable的垃圾回收

参考代码:

参数设置:-Xms15m -Xmx15m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails

public class StringTest09 {public static void main(String[] args) {for (int i = 0; i < 1000000; i++) {String.valueOf(i).intern();}}
}

 

 

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

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

相关文章

MR外包团队:MR、XR混合现实技术应用于游戏、培训,心理咨询、教育成为一种创新的各行业MR、XR形式!

随着VR、AR、XR、MR混合现实等技术逐渐应用于游戏开发、心理咨询、培训、教育各个领域&#xff0c;为教育、培训、心理咨询等行业带来了全新的可能性。MR、XR游戏开发、心理咨询是利用虚拟现实技术模拟真实场景&#xff0c;让学生身临其境地参与学习和体验&#xff0c;从而提高…

为什么UI自动化难做?—— 关于Selenium UI自动化的思考

在快速迭代的产品、团队中&#xff0c;UI自动化通常是一件看似美好&#xff0c;实际“鸡肋”&#xff08;甚至绝大部分连鸡肋都算不上&#xff09;的工具。原因不外乎以下几点&#xff1a; 1 效果有限 通常只是听说过&#xff0c;就想去搞UI自动化的团队&#xff0c;心里都认…

SpringSecurity6从入门到上天系列第六篇:解决这个问题为什么在引入SpringSecurity之后所有的请求都需要先做登录认证才可以进行访问呢

文章目录 问题引入 1&#xff1a;问题阐述 2&#xff1a;问题分析 一&#xff1a;从SpringBoot的自动装配 1&#xff1a;SpringBootApplication介绍 2&#xff1a;自动装配的核心方法 3&#xff1a;核心方法的调用路径 4&#xff1a;SpringSecurity核心配置 5&#xf…

总结1057

考研倒计38天 极限冲刺day1 今日共计学习13h33m&#xff0c;为了能走出备考的低谷阶段&#xff0c;来一场与自我的较量。在尽可能保证效率的情况下&#xff0c;玩命干。考研这件事&#xff0c;从来不是因为看到了希望才去努力&#xff0c;而是玩命努力后才看到希望。

蒙HarmonyOS从零实现类微信app效果第二篇,我的+发现页面实现

本着不拖更的原则&#xff0c;今天上新了&#xff0c;今天实现了类微信app的发现页和我的页面。先看效果。 效果是不是看着还不错。其实这两个页面功能实现还是比较简单的&#xff0c;接下来还是老规矩&#xff0c;先进行页面的拆分和代码实现&#xff0c;然后进行相关我认为比…

2023年亚太杯APMCM数学建模大赛数据分析题MySQL的使用

2023年亚太杯APMCM数学建模大赛 以2022年C题全球变暖数据为例 数据分析&#xff1a; 以2022年亚太杯数学建模C题为例&#xff0c;首先在navicat建数据库然后右键“表”&#xff0c;单击“导入向导”&#xff0c;选择对应的数据格式及字符集进行数据导入 导入之后&#xff0c…

c# 字符串转化成语音合成,System.Speech

C# 语音合成可以使用 System.Speech.Synthesis 命名空间中的 SpeechSynthesizer 类来实现。SpeechSynthesizer 类提供了一系列方法和属性&#xff0c;可以用来控制语音合成的过程&#xff0c;包括设置语音、音调、语速等。 下面是一个简单的示例&#xff0c;用来演示如何使用 …

[量子计算与量子信息] 2.1 线性代数

2.1 线性代数 符号对照表 量子力学中&#xff0c;向量使用 ∣ ψ ⟩ \ket \psi ∣ψ⟩ (ket)来表示&#xff0c;可以理解为一个列向量。其对偶向量为 ⟨ ψ ∣ \bra \psi ⟨ψ∣ &#xff0c;可以理解为行向量。 向量空间中零向量直接用 0 0 0 表示&#xff0c; ∣ 0 ⟩ \…

卸载本地开发环境,拥抱容器化开发

以前在公司的时候&#xff0c;使用同事准备的容器化环境&#xff0c;直接在 Docker 内进行开发&#xff0c;爽歪歪呀。也是在那时了解了容器化开发的知识&#xff0c;可惜了&#xff0c;现在用不到那种环境了。所以打算自己在本地也整一个个人的开发环境&#xff0c;不过因为我…

S-Clustr(影子集群) 重磅更新!黑入工业PLC设备!

公告 项目地址:https://github.com/MartinxMax/S-Clustr 更新预告内容进度SIEMENS S7-200 SMART远程控制进行中 开发人员Blog联系方式提交时间提交内容授权情况ASH_HHhttps://blog.csdn.net/m0_53711047/article/details/133691537?spm1001.2014.3001.5502匿名2023-10-16 2…

USB复合设备构建CDC+HID鼠标键盘套装

最近需要做一个小工具&#xff0c;要用到USB CDCHID设备。又重新研究了一下USB协议和STM32的USB驱动库&#xff0c;也踩了不少坑&#xff0c;因此把代码修改过程记录一下。 开发环境&#xff1a; ST-LINK v2 STM32H743开发板 PC windows 11 cubeMX v6.9.2 cubeIDE v1.13.2 cub…

Feature Pyramid Networks for Object Detection(2017.4)

文章目录 Abstract1. Introduction3. Feature Pyramid NetworksBottom-up pathwayTop-down pathway and lateral connections 7. Conclusion FPN Abstract 特征金字塔是识别系统中检测不同尺度物体的基本组成部分。但最近的深度学习对象检测器避免了金字塔表示&#xff0c;部分…

VS Code画流程图:draw.io插件

文章目录 简介快捷键 简介 Draw.io是著名的流程图绘制软件&#xff0c;开源免费&#xff0c;对标Visio&#xff0c;用过的都说好。而且除了提供常规的桌面软件之外&#xff0c;直接访问draw.io就可以在线使用&#xff0c;堪称百分之百跨平台&#xff0c;便捷性直接拉满。 那么…

重生之我是一名程序员 31

大家晚上好&#xff01;前面给大家分享了指针与数组的知识&#xff0c;所以今天要给大家分享的知识是——指针数组 相信大家在这里都会有疑问&#xff0c;指针数组是指针还是数组&#xff1f; 在这我们可以类⽐⼀下其他类型的数组&#xff0c;比如整型数组是存放整型的数组&am…

python科研绘图:绘制X-bar图

目录 1.X-bar 图的基本概念 2.X-bar 图的绘制过程 3.X-bar 图的优势 4.X-bar 图的绘制 1.X-bar 图的基本概念 X-bar控制图是一种统计工具&#xff0c;用于监控和控制生产过程中的质量变量。它是过程能力分析和统计过程控制&#xff08;SPC&#xff0c;Statistical Process…

SystemVerilog学习 (5)——接口

一、概述 验证一个设计需要经过几个步骤&#xff1a; 生成输入激励捕获输出响应决定对错和衡量进度 但是&#xff0c;我们首先需要一个合适的测试平台&#xff0c;并将它连接到设计上。 测试平台包裹着设计,发送激励并且捕获设计的输出。测试平台组成了设计周围的“真实世界”,…

Python---数据序列中的公共方法

公共方法就是 支持大部分 数据 序列。 常见公共方法---简单 运算符描述支持的容器类型合并字符串、列表、元组*复制字符串、列表、元组in元素是否存在字符串、列表、元组、字典not in元素是否不存在字符串、列表、元组、字典 案例&#xff1a; 合并 代码&#xff1a; # …

【Nginx】nginx | 微信小程序验证域名配置

【Nginx】nginx | 微信小程序验证域名配置 一、说明二、域名管理 一、说明 小程序需要添加头条的功能&#xff0c;内容涉及到富文本内容显示图片资源存储在minio中&#xff0c;域名访问。微信小程序需要验证才能显示。 二、域名管理 服务器是阿里云&#xff0c;用的宝塔管理…

【探索Linux】—— 强大的命令行工具 P.15(进程间通信 —— system V共享内存)

阅读导航 引言一、system V的概念二、共享内存(1) 概念(2) 共享内存示意图(3) 共享内存数据结构 三、共享内存的使用1. 共享内存的使用步骤&#xff08;1&#xff09;包含头文件&#xff08;2&#xff09;获取键值&#xff08;ftok函数&#xff09;&#xff08;3&#xff09;创…

计算机视觉基础(7)——相机基础

前言 从这一节开始&#xff0c;我们来学习几何视觉。中层视觉包括相机模型、单目几何视觉、对极几何视觉和多目立体视觉等。在学习几何视觉最开始&#xff0c;我们先来学习一下相机模型&#xff0c;了解相机的基本原理&#xff0c;了解相机如何记录影像。 一、数字相机 1.1 基…