论坛首页 Java企业应用论坛

优化变成了忧患:String类的split方法引起的内存泄漏

浏览 53047 次
该帖已经被评为精华帖
作者 正文
   发表时间:2010-03-29  
miaow 写道
插个话:楼主怎么会传进一个几百K的字符串再切分的?觉得这场景很特别。


呵呵,这个问题涉及到公司的业务,不方便明说,请见谅。
0 请登录后投票
   发表时间:2010-03-29  
对于本文中提到的为了提升性能而改进的string处理函数,有些背景我依稀还记得:早期的java版本(可能是第一个版本的,jdk1.0还是jdk1.1),运行非常之慢。后来发现系统中的很大性能消耗在字符串处理上,早期版本的jdk的string应该是没有优化的。在后来的jdk版本中进行了大量的优化,字符串处理的性能突飞猛进。

这个记得不是很清晰了,很久以前看到的东西,都快忘了。我猜测substring()和split()里面的优化是不是就是这个事情加入的,可以猜想一下如果我们将这里的优化去掉,每次substring时都new一个char[],然后array copy,毫无疑问的是整个jvm的速度会极大降低。
0 请登录后投票
   发表时间:2010-03-29  
jarfield 写道
鸟哥哥 写道
StringBuffer,StringBuilder,lz能不能也帮看看subString方法有无这问题?我目前在搞j2me,j2me的StringBuffer是没有subString方法的,j2me是没StringBuilder的。


看了JDK6的StringBuffer和StringBuilder。它们没有split方法,但是有subString方法。它们的subString没有本文提到的问题,原因可以看他们的代码,在父类AbstractStringBuilder中。
 public String substring(int start, int end) {
        if (start < 0)
	    throw new StringIndexOutOfBoundsException(start);
	if (end > count)
	    throw new StringIndexOutOfBoundsException(end);
	if (start > end)
	    throw new StringIndexOutOfBoundsException(end - start);
        return new String(value, start, end - start);
}


subString最终还是调用了String的构造函数,该构造函数拷贝了char[],因此是安全的。
public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.offset = 0;
        this.count = count;
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }


而String类的subString调用的是另一个版本String构造函数,该构造函数对于外部类(AbstractStringBuilder)是不可见的。
// Package private constructor which shares value array for speed.
    String(int offset, int count, char value[]) {
	this.value = value;
	this.offset = offset;
	this.count = count;
    }


从该构造函数的访问权限和注释,我们都可以看出,SUN为了优化性能而专门写了这个函数。

看来我没查看清楚。
对于很大的String,用StringBuffer或者StringBuilder好一些。
0 请登录后投票
   发表时间:2010-03-29  
精彩的帖子,标记下
0 请登录后投票
   发表时间:2010-03-29  
真的是受教了
学习还真的得靠工具,靠研读源码才能大幅进步啊
0 请登录后投票
   发表时间:2010-03-29  
很好的经验,谢谢lz

以后会注意类似的问题
0 请登录后投票
   发表时间:2010-03-29  
太让人感动的帖子了。。这才是je上的应有的水平啊。
0 请登录后投票
   发表时间:2010-03-29  
http://www.artima.com/forums/flat.jsp?forum=106&thread=252441&start=60&msRange=15 << 这一页第一个回复也提及了。
其实这个是老问题了……不过楼主的切入方式还是有趣的。
0 请登录后投票
   发表时间:2010-03-29  
小char型引用split的大String。然后装入hashMap。
由于是引用,GC不回收,每次请求如是。所以造成很大的内存浪费。
这点是很需要注意的。
多谢LZ。
0 请登录后投票
   发表时间:2010-03-29   最后修改:2010-03-29
miaow 写道
插个话:楼主怎么会传进一个几百K的字符串再切分的?觉得这场景很特别。

很有可能是这样的
爬虫把页面爬出来后
统计某些单词的使用频率
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics