`

String.substring()方法简单理解(续)

阅读更多

上一篇博文(http://woyixiaorenne.iteye.com/blog/2305280)说到JDK1.6和1.7的String.substring()的实现出现了变化,那么究竟为什么会变化呢?

注:本文大部分内容是参考或者复制作者的内容,附上原文地址http://www.importnew.com/7418.html

1、当substring()被调用的时候,内部发生什么事?

你或许会认为由于x是不可变的对象,当x被x.substring(1,3)返回的结果赋值后,它将指向一个全新的字符串如下图:




 
然而,这个图并不完全正确,或者说并没有完全表示出java 堆中真正发生的事情。

2. JDK6中的substring()

java中字符串是通过字符数组来支持实现的,在JDK6中,String类包含3个域,char[] value、int offset、int count。分别用于存储真实的字符数组、数组的偏移量,以及String所包含的字符的个数。

当substring()方法被调用的时候,它会创建一个新的字符串对象,但是这个字符串的值在java 堆中仍然指向的是同一个数组,这两个字符串的不同在于他们的count和offset的值。和我们之前说的一致,即新创建的String对象和原来的对象是共用同一个value数组,即指向相同的内存空间(并没有重新开辟新的内存空间),而只是通过offset和count来确定新的字串的值。

内存中情况是:



 
 3. jdk6中substring()将会导致的问题

如果你有一个非常长的字符串,但是你仅仅只需要这个字符串的一小部分,这就会导致性能问题(译注:可能会造成内存泄露,这个bug很早以前就有提及),因为你需要的只是很小的部分,而这个子字符串却要包含整个字符数组,在jdk6中解决办法就是使用下面的方法,它会指向一个真正的子字符串。

1 x = x.substring(x, y) + ""

 4. 在JDK7中有所改进,substring()方法在堆中真正的创建了一个新的数组,当原字符数组没有被引用后就被GC回收了.因此避免了上述问题.


 内存中的情况是:



 还有一点,jdk1.7中已经没有了offset和count。

 因为知识比较匮乏,所以前面一篇博文只是简单看了一下源码,知道了1.6和1.7中他们的实现方法发生了变化,但并未想到为什么会改变,看了这篇文章之后,有种恍然大悟的感觉,多查多想。

附上前面所提到的bug:

Description
Name: rmT116609			Date: 02/13/2002


java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

and also

java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Classic VM (build 1.3.0, J2RE 1.3.0 IBM build co130-20010925 (JIT enabled: jitc)
)

DESCRIPTION OF THE PROBLEM :

String.substring() and StringBuffer.substring() attempt to improve performance (and reduce the memory footprint) by sharing the underlying char[] across various Strings.

However, a problem arises in the following scenerio:

1) Create a huge temporary StringBuffer
2) Extract short strings using substring() and place them in long-term storage (in a table of some sort)
3) Delete the StringBuffer, assuming it will be garbage-collected

However, due to implementation issues the huge StringBuffer will not be garbage collected so long as the substrings extracted from it live. This poses a problem and can potencially lead to huge memory leaks.

I don't necessarily have a solution, but I *did* want to point out this problem. This lead to a memory leak of 10MB/second on my sample app and I only managed to track down the problem by looking at the sources in String.java.

Upon forcing a String copy via getChars(), the memory leak disappeared and the huge buffer was being garabage collected properly.

The API should handle this problem better or at the very least provide extensive documentation on this topic.

This bug can be reproduced always.

Source:

class Test{

public static void main(String a[]) {

 String [] buffer = new String[10000];
 for (int i = 0; i < 10000; i++) 
 {
  buffer[i] = new String(new char[10000000]).substring(0, 1);
 }
}
}

The above is really bad coding, but it demonstrates what is happening. The above will keep references to all char[10000000] instances for as long as buffer[] lives.

CUSTOMER WORKAROUND :
Copy substrings manually; however this makes the code JVM-specific.
(Review ID: 139509) 
======================================================================

                                    
 
Comments
 
 

 

 
  • 大小: 21.1 KB
  • 大小: 22.3 KB
  • 大小: 6.3 KB
  • 大小: 29.2 KB
  • 大小: 30 KB
分享到:
评论

相关推荐

    Implementation-of-HTTP.rar_断点续传

    在Java中实现断点续传主要涉及HTTP协议的理解以及对文件I/O操作的熟练掌握。下面我们将深入探讨这个主题。 首先,了解HTTP协议的基本原理是必要的。HTTP(超文本传输协议)是应用层协议,用于从Web服务器传输超文本...

    C#字符串和正则表达式《续》

    C#提供了丰富的字符串方法,如`Substring`用于提取子字符串,`Replace`用于替换特定字符或子串,`Split`用于根据分隔符拆分字符串,`Trim`用于去除字符串两端的空白字符等。此外,`string.Format`允许格式化字符串...

    java基础教程(续)~~~

    10. **字符串**:Java中的String类是处理文本的重要工具,学习其常用方法如concat(), substring(), equals()等。 11. **异常处理**:理解try-catch-finally语句,以及如何处理和抛出异常,以编写健壮的代码。 12. ...

    用Java设计下载软件

    2. **断点续传**:当下载过程中出现网络中断等情况时,能够继续从上次停止的位置开始下载,避免重复下载已下载的部分,节省时间和带宽资源。 3. **错误处理与恢复**:确保软件能够正确处理各种网络异常情况,并能够...

    Java实现多线程断点下载实例代码(下载过程中可以暂停)

    String fileName = conn.getURL().getPath().substring(conn.getURL().getPath().lastIndexOf("/") + 1); // 获取文件大小 int fileLength = conn.getContentLength(); // 创建本地文件,大小与服务器文件一致 ...

    java范例开发大全(pdf&源码)

    实例90 如何使用substring()方法截取子串 118 实例91 分解字符串 119 实例92 字母大小写转换 120 实例93 去除多余的空白 120 实例94 原始数组类型的String形式 121 实例95 Java合法标识符 122 实例96 显示一周各星期...

    Java范例开发大全 (源程序)

     实例90 如何使用substring()方法截取子串 118  实例91 分解字符串 119  实例92 字母大小写转换 120  实例93 去除多余的空白 120  实例94 原始数组类型的String形式 121  实例95 Java合法标识符 122  ...

    java范例开发大全源代码

     实例90 如何使用substring()方法截取子串 118  实例91 分解字符串 119  实例92 字母大小写转换 120  实例93 去除多余的空白 120  实例94 原始数组类型的String形式 121  实例95 Java合法标识符 122...

    java范例开发大全

    实例90 如何使用substring()方法截取子串 118 实例91 分解字符串 119 实例92 字母大小写转换 120 实例93 去除多余的空白 120 实例94 原始数组类型的String形式 121 实例95 Java合法标识符 122 实例96 显示一周各星期...

    Java范例开发大全(全书源程序)

    实例90 如何使用substring()方法截取子串 118 实例91 分解字符串 119 实例92 字母大小写转换 120 实例93 去除多余的空白 120 实例94 原始数组类型的String形式 121 实例95 Java合法标识符 122 实例96 显示一...

Global site tag (gtag.js) - Google Analytics