超越Java 8:紧凑字符串

175 阅读8分钟

在Java 9中引入的紧凑字符串为开发人员提供了他们需要进行切换的唯一原因……

简介

根据一些调查,如JetBrains的调查,Java版本8目前是世界各地开发人员使用最多的,尽管是2014年发布的。

你正在阅读的是一系列题为“超越Java 8”的文章中的第一篇,灵感来自我的书《Java for Aliens》的内容。这些文章将引导读者逐步探索从版本9开始介绍的最重要的功能。目的是让读者意识到从Java 8前进是多么重要,解释最新版本的语言提供的巨大优势。

在本文中,我们将讨论紧凑字符串,这是Java 9引入的一种机制,它代表了放弃Java 8并升级到最新版本之一的最合理原因之一。

剧透警报

String类在统计上是Java编程中使用最多的类。因此,问问我们自己这个类的对象的效率有多高似乎很重要。好消息是,从Java 9开始,这些对象的性能明显优于以前的版本。此外,这种优势实际上是不费吹灰之力就获得的,也就是说,用JVM版本9(或更高)启动我们的程序就足够了,而不需要对我们的代码采取任何预防措施。那么,我们来了解一下什么是紧凑字符串,以及如何使用它们。

在幕后

img

图1–JDK版本8安装文件夹中src.zip文件的位置。

在Java 8之前,类中使用char数组来存储组成字符串的字符。可以通过读取String类的源代码来验证这一点。为此,只需在JDK版本8的安装文件夹中的src.zip文件中搜索String. javafile。

该文件包含标准Java库的所有源文件。

所以,解压后,我们可以在java\lang路径中找到String.java类的来源(事实上String类属于java.lang包)。如果我们用任何编辑器打开这个文件,我们可以验证String类的声明如下(我们已经删除了一些对我们的讨论没有用的注释和其他元素):

因此,直到Java 8,值字符数组的存在意味着为字符串的每个字符分配16位(2字节)内存。

实际上,在大多数应用程序中,我们使用的字符只能存储在8位(1字节)中。因此,为了在我们的程序中获得更高的速度和内存使用性能,在Java 9中,String class的实现已经被修改为由字节数组而不是字符数组支持。以下是Java版本15中String类声明的初始部分,去掉了无趣的元素:

img

图2–JDK版本15安装文件夹中src.zip文件的位置。

从JDK 9,src.zip文件已被移动到lib目录,包已包含在表示模块的文件夹中。所以,String.java源现在在java.base/java/lang文件夹下。实际上,java.base是包含java.lang包的模块的名称。

然而,总是可以使用不太常见的字符,这些字符需要存储在16位(2字节)中。事实上,在String类中,已经实现了一种基于编码器变量的机制,该机制负责为每个字符分配正确的字节量。这种机制被称为紧凑字符串,自Java版本9以来,它是JVM默认使用的方法。编程上没有任何变化,我们将使用字符串,因为我们一直使用它们。然而,Java应用程序会表现得更好。

我们真的要把一半的内存用在字符串上吗?

虽然我们注意到今天String类由字节数组而不是版本8中的char数组支持,但不幸的是,对于Java,不可能先验地确定程序将使用多少内存。事实上,它是由垃圾收集器的复杂机制自动管理的,在每次执行中,我们的程序可以使用非常不同的内存量。此外,在Java中,没有办法像其他语言那样准确地知道在任何给定时间某个对象使用了多少内存。使用基于java.lang.instrument包的仪器接口的策略,可以近似地估计对象的大小,但这不适用于字符串,因为字符串是不可变的对象,在内存中的分配方式不同于其他项。因此,即使紧凑字符串机制似乎意味着内存节省,这既不确定也不可证明。因此,让我们看看在代码示例中使用JDK版本9或更高版本的优势。

示例

让我们考虑下面的例子:

在这个类中,实例化了100,000个字符串(包含最前面的100,000个数字),这些字符串是串联的。此外,计算和打印创建这些实例和连接它们所需的毫秒。

让我们尝试使用JDK版本15.1启动此应用程序5次,并分析输出:

java压缩字符串

在3539毫秒内创建100000个字符串

java压缩字符串

在3548毫秒内创建100000个字符串

java压缩字符串

在3564毫秒内创建100000个字符串

java压缩字符串

在3561毫秒内创建100000个字符串

java压缩字符串

在3609毫秒内创建100000个字符串

我们可以观察到,每次启动应用程序的速度几乎是恒定的,大约是3.5秒。

因此,让我们尝试使用-XX:-Compact Strings选项禁用紧凑字符串,并尝试运行相同的应用程序5次,然后分析结果:

java-XX:-Compact Strings

在8731毫秒内创建100000个字符串

java-XX:-Compact Strings

在8263毫秒内创建100000个字符串

java-XX:-Compact Strings

在8547毫秒内创建100000个字符串

java-XX:-Compact Strings

在8602毫秒内创建100000个字符串

java-XX:-Compact Strings

在8353毫秒内创建100000个字符串

同样,速度方面的性能几乎是恒定的,但比我们使用紧凑型琴弦时差得多。事实上,这个没有紧凑字符串的应用程序的平均执行速度原来是8.5秒左右,而当我们使用紧凑字符串时,平均只有3.5秒左右。这一显著优势为我们节省了近60%的时间。

如果我们直接用Java 8的最新版本(JDK 1.8.0_261)重新编译和重新启动程序,优势就更加明显了:

"C:\Program Files\Java\jdk1.8.0_261\bin\java"Compact Strings Demo

在31113毫秒内创建100000个字符串

"C:\Program Files\Java\jdk1.8.0_261\bin\java"Compact Strings Demo

在30376毫秒内创建100000个字符串

"C:\Program Files\Java\jdk1.8.0_261\bin\java"Compact Strings Demo

在32868毫秒内创建100000个字符串

"C:\Program Files\Java\jdk1.8.0_261\bin\java"Compact Strings Demo

在32508毫秒内创建100000个字符串

"C:\Program Files\Java\jdk1.8.0_261\bin\java"Compact Strings Demo

在35328毫秒内创建100000个字符串

这次性能的下降更加明显:使用JDK 15和紧凑的字符串,应用程序的性能几乎好10倍!当然,这并不意味着所有程序都会有如此大的改进,因为我们的示例完全基于字符串的分配和级联。

关于内存使用的节省,虽然可能,正如我们所说的,但由于垃圾收集器根据当前情况执行复杂的工作,因此无法证明。

结论

在本文中,我们看到了从Java 8向前发展的第一个有效理由。从版本9开始引入的紧凑字符串,允许我们的程序在使用字符串时更加高效。由于String类在统计上是Java程序中使用最多的类,我们可以得出结论,仅仅使用版本大于8的JDK就可以保证我们的应用程序更快的执行速度。我们还发现,不使用紧凑字符串的JDK 15仍然保证了比JDK 8的最新版本高得多的性能。

更新JDK似乎是第一步。

作者笔记

即使忽略最新版本JDK提供的增强安全性,也有很多理由升级您对Java的了解,或者至少升级您自己的Java运行时安装。我的书《Java for Aliens》,启发了《超越Java 8》系列,包含了从头开始学习Java所需的所有信息,并使用了经过20多年经验完善的久经考验的教学方法,使学习变得简单而令人兴奋。它的结构也是为了深化主题,并拥有卓越的知识,可以对你的职业生涯产生影响。

欲了解更多信息,请访问ww.javaforaliens.com.

主题:

java(编程lang.…,架构,字符串,字符

dzone.com/articles/go…

原文链接:dzone.com/