众所周知,JDK中以前String类中的substring方法存在内存泄漏问题,之所以说是以前,是因为JDK1.7及以后的版本已经修复了,我看都说JDK1.6的版本也存在这个问题,但是我本机上安装的1.6看了看源码不存在内存泄漏问题啊,又看了1.7的源码,和我本机的1.6的一样,是不是我的1.6版版其实是1.7的?!唉,不管了,反正1.7版本肯定没有这个问题(1.5及更老版本肯定有)了,大家就放心的用吧。

之所以存在内存泄漏的问题,是因为原先的版本中,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. }

而其中用到的String构造方法是这样的:


  1. // Package private constructor which shares value array for speed.
  2. String(int offset, int count, char value[]) {
  3. this.value = value;
  4. this.offset = offset;
  5. this.count = count;
  6. }

this.value=value这种实现就出现问题了,因为String类中有几个私有的成员变量:


  1. /** The value is used for character storage. */
  2. private final char value[];
  3. /** The offset is the first index of the storage that is used. */
  4. private final int offset;
  5. /** The count is the number of characters in the String. */
  6. private final int count;
  7. /** Cache the hash code for the string */
  8. private int hash; // Default to 0

明白了吧,这种实现还在引用着原先字符串变量的value[],通过offset和count返回一个长得像的“截取”后的字符串给人一种错觉,导致JVM认为这个最初字符串还在被引用着不对其gc,不过之所以这么做SUN公司(oracle 10年收购了)的JDK编写人员也是有原因的,就是效率问题,如注释所说:

Package private constructor which shares value array for speed.

这样导致的后果就是如果有一个很大很长的字符串我只需要其中的一小部分字符串用substring实现的话,如果让你看似得到的“新”的短小字符串一直没被JVM 回收的话,那么相当这个最初的大字符串也没被回收,尤其是你把这个短小“新”的字符串直接以引用的形式付给一个静态的全局变量,在加上如果访问数量很大,那应该“代价”还是蛮可观的,不过可以简单的这样new(s.substring())就避免了这个问题。

新的JDK中substring之所以不存在这个问题了,是因为这个构造方法改成这样了:


  1. public String(char value[], int offset, int count) {
  2. if (offset < 0) {
  3. throw new StringIndexOutOfBoundsException(offset);
  4. }
  5. if (count < 0) {
  6. throw new StringIndexOutOfBoundsException(count);
  7. }
  8. // Note: offset or count might be near -1>>>1.
  9. if (offset > value.length - count) {
  10. throw new StringIndexOutOfBoundsException(offset + count);
  11. }
  12. this.offset = 0;
  13. this.count = count;
  14. this.value = Arrays.copyOfRange(value, offset, offset+count);
  15. }

其中 value变量不再引用了而是重新新建了一个,所以没有这个问题了,是不是大家看完之后对这个方法有了更全新的认识?

转载请注明—作者:Java我人生(陈磊兴)   原文出处:http://blog.csdn.net/chenleixing/article/details/43646255

       最后,认真看过的网友们,大神们,如有感觉我这个程序猿有哪个地方说的不对或者不妥或者你有很好的

议或者建议或点子方法,还望您大恩大德施舍n秒的时间留下你的宝贵文字(留言),以便你,我,还有广大的程序猿们更快地成长与进步.......



String中substring方法内存泄漏问题的更多相关文章

  1. Android中常见的内存泄漏

    为什么会产生内存泄漏? 当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏. ...

  2. JDK6和JDK7中String的substring()方法及其差异

    翻译人员: 铁锚 翻译日期: 2013年11月2日 原文链接: The substring() Method in JDK 6 and JDK 7   在JDK6与JDK7这两个版本中,substri ...

  3. android中常见的内存泄漏和解决的方法

    android中的内存溢出预计大多数人在写代码的时候都出现过,事实上突然认为工作一年和工作三年的差别是什么呢.事实上干的工作或许都一样,产品汪看到的结果也都一样,那差别就是速度和质量了. 写在前面的一 ...

  4. JDK6与JDK7中String类subString()方法的区别

    1.subString()方法的作用 subString(int beginIndex, int endIndex)方法的返回的是以beginIndex开始到 endIndex-1结束的某个调用字符串 ...

  5. 菜鸟译文(三)——JDK6和JDK7中substring()方法的对比

    substring(int beginIndex, int endIndex)方法在JDK6和JDK7中是不同的.了解他们的区别可以让我们更好的使用这个方法.方便起见,以下用substring() 代 ...

  6. .NET中常见的内存泄漏和解决办法

    在.NET中,虽然CLR的GC垃圾回收器帮我们自动回收托管堆对象,释放内存,最大程度避免了"内存泄漏"(应用程序所占用的内存没有得到及时释放),但.NET应用程序"内存泄 ...

  7. PerfView专题 (第三篇):如何寻找 C# 中的 VirtualAlloc 内存泄漏

    一:背景 上一篇我们聊到了如何用 PerfView 去侦察 NTHeap 的内存泄漏,这种内存泄漏往往是用 C 的 malloc 或者 C++ 的 new 分配而不释放所造成的,这一篇我们来聊一下由 ...

  8. java String 中 intern方法的概念

    1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...

  9. android 中如何分析内存泄漏

    转载:http://blog.csdn.net/fulinwsuafcie/article/details/8363218 前提条件: 1,电脑安装了java 运行环境 2,手机端开启了 USB 调试 ...

随机推荐

  1. 51NOD——N 1107 斜率小于0的连线数量

    https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1107 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 ...

  2. Qt5 UI信号、槽自动连接的控件重名大坑(UI生成的槽函数存在一个隐患,即控件重名。对很复杂的控件,不要在 designer 里做提升,而是等到程序启动后,再动态创建,可以避免很多问题)

    对Qt5稍有熟悉的童鞋都知道信号.槽的自动连接机制.该机制使得qt designer 设计的UI中包含的控件,可以不通过显式connect,直接和cpp中的相应槽相关联.该机制的详细文章见 http: ...

  3. docker安装及问题处理

    1.在Ubuntu的命令行中输入 sudo apt-get install docker.io 2.如果切换到了root用户下 apt-get install docker.io 3.对于新安装的Ub ...

  4. pcb过孔盖油

    pcb的过孔应该盖油,,这样,两个距离比较紧的过孔就不会在焊接的时候短路了,尤其是手工焊接小件的时候.

  5. AES 加密解密

    package XX.XX.XX.test; import java.io.IOException; import java.io.UnsupportedEncodingException; impo ...

  6. RISC-V工具链环境(基于Debian/Linux操作系统)

    RISC-V工具链环境(基于Debian/Linux操作系统) 提要 Debian/Linux虚拟机导入 启动虚拟机 SiFive/Nuclei SDK运行指南 Debian/Linux虚拟机存储位置 ...

  7. 对延时敏感的应用是否应该使用Docker?

    在High Scalability上看到一篇文章 How Does The Use of Docker Effect Latency? .文章回答了一个问题 I keep hearing about ...

  8. hadoop配置文件的加载机制 分类: A1_HADOOP 2015-01-21 11:29 839人阅读 评论(0) 收藏

    hadoop通过Configuration类来保存配置信息 1.通过Configuration.addResource()来加载配置文件 2.通过Configuration.get***()来获取配置 ...

  9. Android 节日短信送祝福(功能篇:1-数据库操作类与自定义ContentProvider)

    首先,还是展示一下部分目录结构:  在节日短信送祝福的功能实现方面,为了能够方便直观展示实现过程,小编我以Java文件为基础,一个一个来展示,免得到时候这个java文件写点,一下又跳到另外一个java ...

  10. 用户之间imp的问题

    今天同事说申请了一个从生产导出的dump文件,须要导入測试库进行測试. 之前做的基本都是本库导出,本库导入的操作,比如:imp test/***@test tables=tbl_fuel file=H ...