JDK 7和JDK 8中大行读取速度较慢的原因

我之前发布了博客文章“使用JDK 7和JDK 8读取慢速行”,并且在该问题上有一些有用的评论来描述该问题。 这篇文章提供了更多解释,说明为何该文章中演示的文件读取(并由AntLineContainsRegExp使用 )在Java 7和Java 8中比在Java 6中这么慢。

X Wang的帖子JDK 6和JDK 7的substring()方法描述了如何在JDK 6和JDK 7之间更改String.substring() 。Wang在该帖子中写道,JDK 6 substring() “创建了一个新字符串,但字符串的值仍指向堆中相同的[backing char]数组。” 他与JDK 7方法形成对比,“在JDK 7中,substring()方法实际上在堆中创建了一个新数组。”

Wang的文章对于理解Java 6和Java 7之间String.substring()的区别非常有用。这篇文章的评论也很有见地。 这些评论包括我很感激观点 ,“我会说'不同'而不是'改善'。” 也有关于JDK 7如何避免 JDK 6中可能发生的潜在内存泄漏的解释

StackOverflow线程Java 7字符串–子字符串的复杂性解释了更改的动机,并引用了JDK-4513622错误:(str)保留字段的子字符串会阻止对象的GC 。 该错误指出:“ [发生OutOfMemory错误,因为如果调用者在对象中存储字段的子字符串,则对象不会被垃圾回收。” 该错误包含演示此错误发生的示例代码。 我在这里修改了该代码:

/**
 * Minimally adapted from Bug JDK-4513622.
 *
 * {@link http://bugs.java.com/view_bug.do?bug_id=4513622}
 */
public class TestGC
{
   private String largeString = new String(new byte[100000]);
    
   private String getString()
   {
      return this.largeString.substring(0,2);
   }
    
   public static void main(String[] args)
   {
      java.util.ArrayList<String> list = new java.util.ArrayList<String>();
      for (int i = 0; i < 1000000; i++)
      {
         final TestGC gc = new TestGC();
         list.add(gc.getString());
      }
   }
}

下一个屏幕快照展示了用Java 6(jdk1.6是可执行Java启动程序路径的一部分)和Java 8(主机上的默认版本)执行的最后一个代码段(从Bug JDK-4513622改编而成)。 如屏幕快照所示,在Java 6中运行代码时抛出OutOfMemoryError ,而在Java 8中运行时不抛出OutOfMemoryError

demoTestGCForJdk4513622

换句话说,当对冗长的Java字符串执行String.substring时,Java 7中的更改修复了潜在的内存泄漏,但以性能影响为代价。 这意味着使用String.substring (包括Ant的LineContainsRegExp)来处理很长的行的任何实现都可能需要更改以不同的方式实现,或者在从Java 6迁移到Java 7及更高版本时处理很长的行时应避免使用。

一旦知道了问题(在这种情况下更改String.substring实现),就可以更轻松地在线查找有关正在发生的事情的文档(感谢提供了使这些资源易于查找的注释)。 JDK-4513622的重复错误包含提供额外详细信息的内容。 这些错误是JDK-4637640:由于String.substring()实现导致的内存泄漏JDK-6294060:使用substring()导致了内存泄漏 。 其他相关的在线资源包括Java 7中对String.substring的更改 (其中包括对String.intern()的引用-有更好的方法 ), Java 6与Java 7:当实现很重要时 ,以及受到高度评价的(超过350条注释) Reddit线程TIL Oracle更改了Java 7 Update 6中的内部String表示,从而将子字符串方法的运行时间从常量更改为N。

用Java 1.7.0_06进行的更改为String内部表示的文章很好地回顾了此更改,并总结了原始问题,修复程序以及与该修复程序相关的新问题:

现在您可以忘记上面描述的内存泄漏,并且永远不再使用新的String(String)构造函数。 作为缺点,您现在必须记住String.substring现在具有线性复杂度,而不是恒定的复杂度。

翻译自: https://www.javacodegeeks.com/2015/01/reason-for-slower-reading-of-large-lines-in-jdk-7-and-jdk-8.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值