• JDK9 为何要将String的底层实现由char[]改成了byte[]


    优化String节省jvm内存空间的必要性

     (1) 调查统计发现一个Java系统,堆里面存活最多的对象之一就是String对象,所以优化String的占用空间是很有意义的,因为String是实际开发中使用最频繁的类。否则,你去优化一个平时根本不怎么用到的类,那么就很鸡肋了。

    上图是基于Java 8运行的SpringBoot系统对象数量的快照,我们可以看到String对象有82039个,占用了1968936字节的内存,占用内存排在第5位

    这里注意的是Java 8中String内部实现是char[],我们可以看到内存占用排在第2位的就是char[]。

    char[]对象有89140个,内存占用了11354176字节,从个数数量级上来看,你会发现char[]对象其实大部分来源于String对象内部维护的那个char[]。

    (2) 调查统计还发现了一个事实,就是开发者使用到的文本字符串中的字符,大部分使用一个字节来表示就足够了。

    如何优化空间的

    (1) char类型的数据在 JVM 中占用了两个字节的空间,使用的是UTF-16编码。

    JVM 规范中是如下描述的:

    char, whose values are 16-bit unsigned integers representing Unicode code points in the Basic Multilingual Plane, encoded with UTF-16, and whose default value is the null code point ('\u0000')。

    所以使用char[]来表示String就导致了即使String中的字符单个字节就能表示,还是得占用了两个字节,而实际开发中使用频率最高的却是单字节的字符。

    (2) 优化为byte[],并提供了另外一种编码可能性

    仅仅优化为byte[]是不够的,关键是提供了ISO-8859-1/Latin-1编码可能(Latin-1就是ISO-8859-1)。

    Latin-1编码是用单个字节来表示字符,比两个字节的UTF-16节省了一半空间。

    所以String类中多了一个编码标志位coder,用来表示使用的是UTF-16编码,还是Latin-1编码。

    1. /**
    2. * The identifier of the encoding used to encode the bytes in
    3. * {@code value}. The supported values in this implementation are
    4. *
    5. * LATIN1
    6. * UTF16
    7. *
    8. * @implNote This field is trusted by the VM, and is a subject to
    9. * constant folding if String instance is constant. Overwriting this
    10. * field after construction will cause problems.
    11. */
    12. private final byte coder;

    接下来看一个属性COMPACT_STRINGS。

    翻译过来就是压缩字符串,默认静态代码块赋值true;很明显这个就是决定该String对象是否采用压缩策略的关键属性。

    1.  static final boolean COMPACT_STRINGS;
    2.     static {
    3.         COMPACT_STRINGS = true;
    4.     }

    接下来看它的构造器,我们看它最根源的构造器即可。

    像常用的 public String(char value[]),public String(char value[], int offset, int count)里面都调用了这个构造器。

    1. String(char[] value, int off, int len, Void sig) {
    2. //空判断
    3. if (len == 0) {
    4. this.value = "".value;
    5. this.coder = "".coder;
    6. return;
    7. }
    8. //如果开启压缩字符串策略那么就尝试压缩
    9. if (COMPACT_STRINGS) {
    10. byte[] val = StringUTF16.compress(value, off, len);
    11. if (val != null) {
    12. this.value = val;
    13. this.coder = LATIN1;
    14. return;
    15. }
    16. }
    17. //如果没有压缩成功并返回就直接设置为UTF16,我们点进UTF16我们也可以看到下面这两个属性
    18. this.coder = UTF16;
    19. this.value = StringUTF16.toBytes(value, off, len);
    20. }
    21. //点进上面的UTF16找到的两个属性,也就证实了coder属性上面的注解(两个实现)
    22. static final byte LATIN1 = 0;
    23. static final byte UTF16 = 1;

    对于这种:

    String name="jack";

    使用LATIN1编码,占用4个字节就够了,而原来的char[],就得占用8个字节

    对于这种:

    String name="小明";

    没得办法,和char[]表示String没什么区别,即使现在是byte[]来表示String,还是得乖乖用UTF16编码,和优化之前一样,没节省空间(LATIN1编码集支持的字符有限,其中就不支持中文字符,因此才保留了UTF16兜底)。

    优化空间的好处

    单位时间内,

    减少空间->减少触发GC的次数->减少Stop the world activity的次数->提高系统性能

     参考文章:(8 封私信 / 18 条消息) jdk9为何要将String的底层实现由char[]改成了byte[]? - 知乎 (zhihu.com)

    关于String底层使用的是char数组还是byte数组以及一点String面试问题_一古月一的博客-CSDN博客_string底层是byte还是char

  • 相关阅读:
    Springboot集成websocket实现消息推送和在线用户统计
    Mysql的索引
    springboot基础--实现默认登录页面
    安卓TextView的lineHeight*lineCount!=height问题,解决不支持滚动的系统下对多页Text进行分页
    Studio One6.5版本要不要更新?哪些人需要更新?更新了哪些内容
    prettytable:一款像数据库一样可完美格式化输出的 Python 库
    【Qt课设】基于Qt实现的中国象棋
    spring boot集成redis
    Qt不能安装自己想要的版本,如Qt 5.15.2
    Windows 安装 Seata 1.6.1 并配置开机自启
  • 原文地址:https://blog.csdn.net/qq_51409098/article/details/126466943