JDK17新特性之--新的Compact Strings(JEP 254)

news2024/11/16 21:46:14

前言

JDK9将String底层的数据结构从private final char value[];改成了private final byte[] value;
JEP 254: Compact Strings(紧凑字符串),这要修改的目的就是为了节省空间1。我们先看一下JDK9和JDK8中String源码的变化。
JDK9中String源码:

public final class String 
implements java.io.Serializable, Comparable<String>, CharSequence,  
Constable, ConstantDesc {  
    @Stable  
    private final byte[] value;  

    * LATIN1  
    * UTF16  
    private final byte coder;
    
    @Native static final byte LATIN1 = 0;  
    @Native static final byte UTF16 = 1;

JDK8中String源码:

public final class String  
    implements java.io.Serializable, Comparable<String>, CharSequence {  
    private final char value[];  
    private int hash; 
}

对比源码可以看出,在JDK9中使用了byte[]代替了char[]同时还增加了一个 coder标志位表示使用的是LATIN1还是UTF16编码。

节省了多大空间

既然这个升级是为了节省内存空间,那么我们就先来测试一下看看节省了多少空间。我们创建一个简单的Demo,创建一个List然后向里面添加1-20000000个String,再对比一下JDK9和JDK8占用内存空间大小。

public static void main(String[] args) throws InterruptedException {  
        List<String> name= IntStream.range(0,20000000).mapToObj(String::valueOf).collect(Collectors.toList());;  
        System.out.printf("add complete "+name.size());  
        Thread.sleep(100000000L);
}

JDK8内存使用情况

JDK8内存使用情况

JDK9内存使用情况

JDK9内存使用情况

从图中可以看出同样是1-20000000字符串JDK8中char[]占用了742MB,JDK9中byte[]占用了559MB,节省了32.7%内存空间。

没有Jprofile 也可以使用jps+jmap查看内存占用情况,以下为Windows操作

  1. .\jps.exe 获取出PID
PS C:\Program Files\Java\jdk1.8.0_191\bin> .\jps.exe
9328 RemoteMavenServer36
9744 Launcher
10548
2196 Jps
7224 RemoteMavenServer36
8120 Main
  1. 通过Jmap查看内存中对象统计
JDK8:
PS C:\Program Files\Java\jdk1.8.0_191\bin> .\jmap.exe -histo:live 8120

 num     #instances         #bytes  class name
----------------------------------------------
   1:      20004394      640375664  [C
   2:      20004267      480102408  java.lang.String
   3:           639       83113224  [Ljava.lang.Object;
   4:           685          77712  java.lang.Class
   5:           791          31640  java.util.TreeMap$Entry
   6:            26          25752  [B
   7:           657          21024  java.util.HashMap$Node
   8:           315          13488  [Ljava.lang.String;
   9:           126           8272  [I
  10:           123           7872  java.net.URL
  
JDK9:

PS C:\Program Files\Java\jdk1.8.0_191\bin> .\jmap.exe -histo:live 4116
 num     #instances         #bytes  class name (module)
-------------------------------------------------------
   1:      20003758      480237256  [B (java.base@17.0.7)
   2:      20003674      480088176  java.lang.String (java.base@17.0.7)
   3:          1042       83141776  [Ljava.lang.Object; (java.base@17.0.7)
   4:           137         142376  [C (java.base@17.0.7)
   5:           818         100864  java.lang.Class (java.base@17.0.7)
   6:          1242          39744  java.util.HashMap$Node (java.base@17.0.7)
   7:          1084          34688  java.util.concurrent.ConcurrentHashMap$Node (java.base@17.0.7)
   8:           330          30240  [Ljava.util.HashMap$Node; (java.base@17.0.7)
   9:           336          16128  java.util.HashMap (java.base@17.0.7)
  10:            22          15392  [Ljava.util.concurrent.ConcurrentHashMap$Node; (java.base@17.0.7)

从Jmap输出内存对象统计来看 JDK8中[C就是 char[] ,实例数有2000万多点,占用内存610MB,JDK9 [B 就是byte[],实例数也是2000万多点,占用内存457MB,节省内存33.4%。值的注意的是如果不想使用字符串压缩可以使用 -XX:-CompactStrings JVM参数来禁用此功能

是怎么节省空间的

JAVA中一个char到底占用多大空间?在JVM规范中char是使用一个16-bit无符号整型来表示一个Unicode code2,所以一个char可以理解占用两个字节空间,但是我们可以想一下常用的ascii码其实只要一个字节就能表示了。JDK9里对Latin-1(又称ISO-8859-1)字符使用一个byte存储,只占用了一个字节,如果不是Latin-1字符就使用UTF-16存储,占用两个字节,为此JDK9中增加了coder标志位,这样对于使用最频繁的abcd… 1234…等字母、数字来说就节省了50%空间,然而对于中文或者不在Latin-1字符来说还是和以前一样,并不能节省内存空间。那么Latin-1到底有哪些字符呢?Latin-1(也称为ISO 8859-1),是一种字符编码标准,用于表示拉丁字母语系的字符集。它包含了256个字符3

  • 26个基本拉丁字母,包括大小写字母 a-z,A-Z
  • 数字0-9
  • 逗号、句号、问号等常见标点符号
  • 特殊符号,如@、#、$、%等
  • 一些重音符号和其他符号,如é、ç、ñ等
    具体可以看以下图片:
    在这里插入图片描述

总结

1. 更少的内存占用:

采用 Compact Strings 后,只包含 ASCII 字符或者Latin-1的字符串在内存中的占用空间会减少一半,从而可以减少内存的使用量,提高程序的性能。

2.String内置方法都重写了

String内置的方法像equals、compareTo等都重写了。

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

   public int compareTo(String anotherString) {
        byte v1[] = value;
        byte v2[] = anotherString.value;
        byte coder = coder();
        if (coder == anotherString.coder()) {
            return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
                                   : StringUTF16.compareTo(v1, v2);
        }
        return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
                               : StringUTF16.compareToLatin1(v1, v2);
     }

3.更快的字符串操作:

由于 Compact Strings 的内部表示方式采用了byte[]存储数据,可以更快地执行字符串操作,例如字符串比较、拼接等。

String生成测试Demo:

        Long startTime=System.currentTimeMillis();
        List<String> name= IntStream.range(0,20000000).mapToObj(String::valueOf).collect(Collectors.toList());;
        System.out.println("add  "+name.size()+" complete ,cast "+(System.currentTimeMillis()-startTime)+"ms"); 
       //JDK9:
       add  20000000 complete ,cast 1313ms
       //JDK8
       add  20000000 complete ,cast 13777ms

从生成2000万个String速度来看,JDK9只花了1.3S,而JDK8花了13S,确实快了不少。

String拼接Demo:

        Long startTime = System.currentTimeMillis();
        List<String> name = IntStream.range(0, 20000000).mapToObj(x -> String.valueOf(x) + x).collect(Collectors.toList());
        System.out.println("add  " + name.size() + " complete ,cast " + (System.currentTimeMillis() - startTime) + "ms");
  //JDK9
  add  20000000 complete ,cast 1832ms
  //JDK8
  add  20000000 complete ,cast 25147ms
        

从拼接2000万个String速度来看,JDK9只花了1.8S,而JDK8花了25S,确实也快了不少。

4.更高的兼容性:

Compact Strings 不会影响现有的 Java 代码,因此可以与现有的 Java 应用程序兼容,无需修改代码,这点是肯定的,如果要修改Java String操作的代码全球有多少人要抓狂,最后肯定都选择不升级了。


  1. JEP 254: Compact Strings (openjdk.org) ↩︎

  2. (11 封私信) Java中关于Char存储中文到底是2个字节还是3个还是4个? - 知乎 (zhihu.com) ↩︎

  3. ISO/IEC 8859-1 - Wikipedia ↩︎

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

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

相关文章

深度学习技巧应用12-神经网络训练中批归一化的应用

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用12-神经网络训练中批归一化的应用,在深度学习中,批归一化(Batch Normalization,简称BN)是一种重要的技巧,它在许多神经网络中都得到了广泛应用。本文将详细介绍批归一化的原理和应用,并结合PyTorch框架构建一个简…

法规标准-SAE J2802标准解读

SAE J2802是做什么的&#xff1f; SAE J2802全名为盲点监测系统&#xff08;BSMS&#xff09;&#xff1a;工作特性和用户界面&#xff0c;其中主要是对BSMS系统的工作特性及用户界面进行了介绍 BSMS目标 强制性目标 任何可获得公路许可的车辆&#xff0c;此处视为大于125 …

深入浅出二叉树— C语言版【数据结构】

目录 ​编辑 1.树概念及结构 1.1树的概念 1.2 树的相关概念 ​1.3 树的表示 2.二叉树概念及结构 2.1概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 简单二叉树题目练习 2.5 二叉树的存储结构 2.5.1 顺序存储——堆 2.5.2 链式存储 1.树概念及结构 1.1树的概念 树…

Java --- String类

&#xff08;一&#xff09;String java.lang.String 类代表字符串。Java 程序中所有的字符串文字&#xff08;例如 "hello" &#xff09;都可以看作是实现此类的实例。 字符串是常量&#xff0c;用双引号引起来表示。它们的值在创建之后不能更改。 字符串 St…

深度卷积图神经网络(Deep Convolutional Graph Neural Network,DCGNN)的基本概念与应用

目录 一、引言 1.1 神经网络的发展历程 1.2 图神经网络的出现 二、深度卷积图神经网络的基本概念 2.1 图的表示 2.2 图卷积神经网络 2.3 深度卷积图神经网络 三、深度卷积图神经网络的应用 3.1 图像分类 3.2 图像分割 3.3 图像生成 四、深度卷积图神经网络的优缺点 …

【数据结构与算法】图的概述(内含源码)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️数据结构与算法】 学习名言&#xff1a;天子重英豪&#xff0c;文章教儿曹。万般皆下品&#xff0c;惟有读书高——《神童诗劝学》 系列文章目录 第一章 ❤️ 学前知识 第二章 ❤️ 单向链表 第三章…

分布式一致性Hash算法原理及实现

文章目录 一致性Hash原理提高容错性和和扩展性一致性Hash实现思路代码 一致性Hash原理 简单来说&#xff0c;一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环&#xff0c; 如假设某哈希函数 H 的值空间为 0 ~ 2^32-1&#xff08;即哈希值是一个32位无符号整形&#xff09;…

搜狗百科怎么创建?搜狗百科创建指南(经验分享)

搜狗百科是一个允许用户创建、编辑和维护百科全书的网站。它是搜狗搜索旗下的一个产品&#xff0c;为用户提供了一个共享知识的平台。创建一个搜狗百科词条并非难事&#xff0c;但需要遵守一些注意事项。 话不多说。小媒同学将介绍搜狗百科词条的创建过程和注意事项。 一、创建…

java基础入门-04-【集合学生管理系统】

Java基础入门-04-【集合&学生管理系统】 11、集合&学生管理系统11.1.ArrayList集合和数组的优势对比&#xff1a;11.1.1 ArrayList类概述11.1.2 ArrayList类常用方法11.1.2.1 构造方法11.1.2.2 成员方法11.1.2.3 示例代码 11.1.3 ArrayList存储字符串并遍历11.1.3.1 案…

【观察】甲骨文以“双引擎”驱动,加速中国企业拥抱决策智能

毫无疑问&#xff0c;当前中国整体经济形态正在从传统经济向数字经济转型&#xff0c;千行百业也在加速数字化转型&#xff0c;特别是随着企业数据的沉淀越来越庞大&#xff0c;对数据平台以及智能决策等新技术的需求也越来越旺盛。 国家发布的《“十四五”数字经济发展规划》中…

视频里的音乐怎么转换成mp3格式?

视频里的音乐怎么转换成mp3格式&#xff1f;视频里的音乐转换为mp3的原因有很多&#xff0c;主要是因为mp3格式是一种音频格式&#xff0c;文件大小较小&#xff0c;更易于存储和传输。相比之下&#xff0c;视频格式则是一种视频文件格式&#xff0c;虽然包含音频&#xff0c;但…

Q-in-Q 和 MAC-in-MAC

例题引入&#xff1a; 1. 城域以太网在各个用户以太网之间建立多点第二层连接&#xff0c;IEEE802.1ad定义运营商网桥协议提供的基本技术是在以太网帧中插入&#xff08;26&#xff09;字段&#xff0c;这种技术被称为&#xff08;27&#xff09;技术。 (26)A.运营商VLAN标记…

Hive知识点的回顾

一、Hive的序列化和反序列化 Hive读取文件机制&#xff1a;读取文件中的每一行 > 反序列化 > 通过分隔符进行切割&#xff0c;返回数据表中的每一行对象。 Hive写文件机制&#xff1a;把数据表中的每一行Row对象 > 调用LazySimpleSerde类中的序列化方法 > 把Row对象…

基于AT89C51单片机的电子秒表设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87759735?spm1001.2014.3001.5503 源码获取 主要内容&#xff1a; 设计一个电子钟,实现对时、分、秒的显示的控制,电路采用24小时计时方式。另一个功能是秒表功能…

JVM内存模型和结构介绍

什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一个虚构出来的计算机&#xff0c;有着自己完善的硬件架构&#xff0c;如处理器、堆栈等。 为什么需要JVM&#xff1f; Java语言使用Java虚拟机屏蔽了与具体平台相关的信息&…

执行网格中有特定数量节点的传感器网络部署(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 ​无线传感器网络是通过大量分布的传感器节点作为终端来协同感知和自主地监测外部世界,以多跳、自组织或协作的方式进行通信和…

Java 基础进阶篇(十二)—— Arrays 与 Collections 工具类

文章目录 一、Arrays工具类1.1 Arrays 类常用方法1.2 对于 Comparator 比较器的支持1.3 Arrays 的综合应用1.3.1 应用一&#xff1a;数组的降序排序1.3.2 应用二&#xff1a;根据学生年龄进行排序 二、Collections工具类2.1 Collections 类常用方法2.2 Collections 排序相关 AP…

哈希表相关知识总结

一、哈希表的定义 散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在内存存储位置的数据结构。也就是说&#xff0c;它通过计算一个关于键值的函数&#xff0c;将所需查询的数据映射到表中一个位置…

C++相比于C语言增加的8个特性(详解)

C相比于C语言增加的8个特性&#xff08;详解&#xff09; 文章目录 C相比于C语言增加的8个特性&#xff08;详解&#xff09;一、命名空间二、C输入和输出三、缺省参数四、函数重载五、引用六、内联函数七、auto关键字八、指针空值nullptr总结 一、命名空间 c的命名空间是为了…

【刷题之路】LeetCode 21. 合并两个有序链表

【刷题之路】LeetCode 21. 合并两个有序链表 1、题目描述二、解题1、方法1——直接合并1.1、思路分析1.2、代码实现 2、方法2——递归2.1、思路分析2.2、代码实现 1、题目描述 原题连接&#xff1a; 21. 合并两个有序链表 题目描述&#xff1a; 将两个升序链表合并为一个新的 …