博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
string深入之subString
阅读量:6855 次
发布时间:2019-06-26

本文共 3121 字,大约阅读时间需要 10 分钟。

hot3.png

1、应用举例

  subString方法,例如s="abcdef"  s.subString(2,5)结果为cde,长度为endindex-beginindex

2、实现原理

  

[java]  
  1.  /** 
  2.     * Returns a new string that is a substring of this string. The 
  3.     * substring begins at the specified <code>beginIndex</code> and 
  4.     * extends to the character at index <code>endIndex - 1</code>. 
  5.     * Thus the length of the substring is <code>endIndex-beginIndex</code>. 
  6.     * <p> 
  7.     * Examples: 
  8.     * <blockquote><pre> 
  9.     * "hamburger".substring(4, 8) returns "urge" 
  10.     * "smiles".substring(1, 5) returns "mile" 
  11.     * </pre></blockquote> 
  12.     * 
  13.     * @param      beginIndex   the beginning index, inclusive. 
  14.     * @param      endIndex     the ending index, exclusive. 
  15.     * @return     the specified substring. 
  16.     * @exception  IndexOutOfBoundsException  if the 
  17.     *             <code>beginIndex</code> is negative, or 
  18.     *             <code>endIndex</code> is larger than the length of 
  19.     *             this <code>String</code> object, or 
  20.     *             <code>beginIndex</code> is larger than 
  21.     *             <code>endIndex</code>. 
  22.     */  
  23.    public String substring(int beginIndex, int endIndex) {  
  24. if (beginIndex < 0) {  
  25.     throw new StringIndexOutOfBoundsException(beginIndex);  
  26. }  
  27. if (endIndex > count) {  
  28.     throw new StringIndexOutOfBoundsException(endIndex);  
  29. }  
  30. if (beginIndex > endIndex) {  
  31.     throw new StringIndexOutOfBoundsException(endIndex - beginIndex);  
  32. }  
  33. return ((beginIndex == 0) && (endIndex == count)) ? this :  
  34.     new String(offset + beginIndex, endIndex - beginIndex, value);  
  35.    }  

  通过源代码可以发现

    11、string内部通过char[]数组实现

    12、subString方法返回了新的string对象,但是string对象却指向原来得char数组,如果原来的string很大,即使原来的string释放,内存空间也无法回收

    13、offset值默认为0,第一个参数为偏移,第二个为长度,第三个为char数组

[java]  
  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.    }  

      14、默认string构造方法如下:

[java]  
  1.   /** 
  2.     * Initializes a newly created {@code String} object so that it represents 
  3.     * an empty character sequence.  Note that use of this constructor is 
  4.     * unnecessary since Strings are immutable. 
  5.     */  
  6.    public String() {  
  7. this.offset = 0;  
  8. this.count = 0;  
  9. this.value = new char[0];  
  10.    }  

       15、内存泄露测试代码
 

[java]  
  1. package com.string;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class TestSubstringLeak {  
  7.   
  8.     /** 
  9.      * @param args 
  10.      */  
  11.     public static void main(String[] args) {  
  12.         // TODO Auto-generated method stub  
  13.   
  14.         String aa=new String(new char[100000]);  
  15.         List<String> list=new ArrayList<String>();  
  16.         for (int i = 0; i < 10000000; i++) {  
  17.             //虽然截取的字符串占据空间很小,但是由于aa巨大的数组空间被共享,没有释放,所以内存溢出  
  18. //          list.add(aa.substring(2, 3));  
  19.             list.add(new String(aa.substring(2,3)));//加一层构造方法后,构造方法内部进行了数组的拷贝,原有的巨大数组空间被回收,不会内存溢出  
  20.         }  
  21.     }  
  22.   
  23. }  

为了避免内存拷贝、加快速度,Sun JDK直接复用了原String对象的char[],偏移量和长度来标识不同的字符串内容。也就是说,subString出的来String小对象仍然会指向原String大对象的char[],split也是同样的情况 。这就解释了,为什么HashMap中String对象的char[]都那么大。

原因解释

 

    其实上一节已经分析出了原因,这一节再整理一下:

  1. 程序从每个请求中得到一个String大对象,该对象内部char[]的长度达数百K。
  2. 程序对String大对象做split,将split得到的String小对象放到HashMap中,用作缓存。
  3. Sun JDK6对String.split方法做了优化,split出来的Stirng对象直接使用原String对象的char[]
  4. HashMap中的每个String对象其实都指向了一个巨大的char[]
  5. HashMap的上限是万级的,因此被缓存的Sting对象的总大小=万*百K=G级。
  6. G级的内存被缓存占用了,大量的内存被浪费,造成内存泄露的迹象。

解决方案

 

    原因找到了,解决方案也就有了。split是要用的,但是我们不要把split出来的String对象直接放到HashMap中,而是调用一下String的拷贝构造函数String(String original),这个构造函数是安全的,具体可以看代码:

转载于:https://my.oschina.net/hanruikai/blog/158034

你可能感兴趣的文章