`

主题:subString方法中的小“陷阱”

阅读更多

今天在工作中遇到一个问题,花了很久才解决,现在与大家分享一下。
问题的具体情况是这样的,我们的程序会从一个文本文件中读取数据。这个文件每行大概有1000个字符左右,但是我们需要的只是其中固定位置的10个字符左右的一段数据。具体的做法是每次都读取一行,然后使用subString来获取我们需要的值。之后将原来的大的字符串抛弃,将读取的小的字符串保存在一个Set中。
这段逻辑在进行JUnit测试的时候没有发现什么问题,但是在进行大数据量的性能测试的时候,确出现了占用大量内存的问题(远远超出了我们估计的内存使用量)。使用内存分析工具来查看,发现保存在Set中的字符串对象大小明显异常。这是为什么呢?
我们使用Debug来检查这段代码,发现一个奇怪的问题。我们从一个1000字符的字符串中subString了一段10字符的字符串。但是查看subString的value属性的时候,value还是一个1000字符的字符数组,而不是我们想象中的10个字符的字符数组。这是为什么呢?
Code just do what you tell it to do. 代码只会做你让它做的事情。那么就让我们看看Java的源码吧。下面就是subString方法的源码:

  1. public String substring(int beginIndex, int endIndex) {
  2.         if (beginIndex < 0) {
  3.             throw new StringIndexOutOfBoundsException(beginIndex);
  4.         }
  5.         if (endIndex > count) {
  6.             throw new StringIndexOutOfBoundsException(endIndex);
  7.         }
  8.         if (beginIndex > endIndex) {
  9.             throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
  10.         }
  11.         return ((beginIndex == 0) && (endIndex == count)) ? this :
  12.             new String(offset + beginIndex, endIndex - beginIndex, value);
  13.     }
复制代码

看看倒数第二行,这就是原因。Java源码并不是我们想象的那样将原来的字符串的value截取一段赋给新的字符串,而是直接将原来字符串的value赋给新字符串,然后通过制定offset和length的方法来创建新的字符串。原因找到了,修改起来就很简单,不必多说了。
Java这样做的好处是避免了内存的拷贝,对于String这样很基础的类来说,这样可以提高程序的效率。但是这个小小的“陷阱”,花费了我半天的时间。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics