当前位置:Java -> 最近Java版本中字符串去重性能的下降
字符串去重是一项旨在通过从堆内存中消除重复字符串来优化内存使用的重要功能。然而,最近的观察表明了一种令人担忧的趋势——在较新的Java版本中,字符串去重性能出现了下降。因此,我们进行了一项比较分析,以评估Java版本11、17和21中字符串去重性能行为。本文旨在分享我们从此分析中得出的观察和见解。
为了对字符串去重进行实验,我们使用了一个基于Spring Boot开发的开源Web爬虫应用。这个Web爬虫是一个基于REST的应用,它将爬取任何给定的网站,并将该网站的信息存档到H2数据库中。当发起HTTP POST请求时,WebCrawler将开始对该网站进行爬取工作,并返回一个jobId。稍后可以使用这个jobId来查询爬取任务的状态。
要对维基百科网站进行爬取,需要传递种子 和深度。深度决定了它应该在多深的层次上爬取网站并提取信息。例如,这个URL将在后台中以深度为100来爬取维基百科网站。
一旦发起POST请求,它将返回jobId作为响应,并且爬取将在后台开始。一旦爬取任务达到深度级别,就会自动停止该特定的爬取任务。
我们将在Java 11、17和21中使用POST请求对这个Web爬虫进行负载测试,并研究字符串去重性能。
要研究字符串去重的行为,必须首先在JVM中启用它。可以通过传递以下JVM参数来实现:
-XX:+UseStringDeduplication
字符串去重事件的性能特征(例如检查了多少字符串,其中有多少被去重,完成整个过程需要多长时间等)可以通过在应用程序中传递以下JVM参数来打印到日志文件中:
-Xlog:stringdedup*=debug:file=string-dup-logfile.log -Xloggc:string-dup-logfile.log
基于上述JVM参数,我们将字符串去重调试事件和GC事件日志消息都指向单一的“string-dup-logfile.log
’ 文件。
有关JVM参数的详细信息,请参阅下面的文章:字符串去重。
我们使用JMeter对WebCrawler应用进行负载测试,模拟了50个用户在约1小时内提交具有相同种子URL和深度的爬取任务的负载。我们提交相同的URL,以便在应用程序中模拟大量重复的字符串。
请注意,此测试是在我的本地笔记本电脑上进行的,其配置是:
操作系统:Windows 11
系统类型:64位操作系统,x64处理器
内存:12 GB
处理器:Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz 1.19 GHz
Java堆大小(即-Xm512mb)
下面的图像显示了上述情况下的JMeter配置:
测试完成后,我们将生成的垃圾回收日志文件上传到在线工具GCeasy进行分析。该工具迅速生成报告,展示了每个测试的Java版本的字符串去重性能指标。以下是工具生成的报告:
下表总结了Java版本间字符串去重关键性能指标:
Java 11 | Java 17 | Java 21 | |
---|---|---|---|
检测字符串 | 1,540,837 | 997,693 | 650,245 |
去重字符串 | 1,342,865 | 505,376 | 299,261 |
去重字符串大小 | 102.4 mb | 39.57 mb | 15.81 mb |
去重百分比 | 34.3 % | 9.3 % | 3.4 % |
去重时间 | 1,264.442 ms | 2,323.492 ms | 3,439.466 ms |
分析显示,Java 11表现出最佳的字符串去重性能,消除了34.3%的字符串。相反,Java 17和21只能消除9.3%和3.4%的字符串。此外,在现代Java版本中,去重字符串所用时间增加,Java 11仅需1,264.442毫秒完成整个过程,而Java 17和21分别需要2,323.492毫秒和3,439.466毫秒。
从本质上讲,现代JVM在检测更多的字符串并消除更少的重复字符串时花费了更多时间。这突显了JVM性能明显下降。
对Java版本11、17和21之间的字符串去重性能进行的调查揭示了JVM行为演变的重要见解。虽然字符串去重作为优化内存利用的重要机制,但我们的分析显示了在较新的Java版本中性能下降的令人担忧的趋势。Java 11表现为卓越的执行者,可以在更短的时间内有效消除大量重复字符串。相反,Java 17和21在被消除的字符串比例以及执行此过程所需的时间方面都表现出了降低的效率。
推荐阅读: 20.为什么Thread类的sleep()和yield()方法是静态的?
本文链接: 最近Java版本中字符串去重性能的下降