日期:2014-05-19  浏览次数:21143 次

巨多字符串,频繁split,内存溢出
008011;100025;1369491001;新绿色田地;2;0;20111027;29991231;70;70;0;;

类似上边的数据,有100多万行.


100多W已成功导入List<String> lines = new ArrayList<String>();

现在要把每一行,按";" 拆分成String[] .我是循环遍历 lines,每一行 用pattern.split() 拆分.

执行到70多W行的时候就内存溢出了. 有木有别的拆分方式,可以避免内存溢出?

我知道加大内存是个方式.但这个方式不能用.

代码:

Java code


        List<String>list=new ArrayList<String>();
        List<String[]>rows = new ArrayList<String[]>();
    String s = "008011;100025;1369491001;新绿色田地;2;0;20111027;29991231;70;70;0;;";
    for(int i=0;i<1500000;i++){
        list.add(s);
    }
        String regex = ";";
        Pattern p = Pattern.compile(regex);
        
        for(int i=0;i<list.size();i++){
            String line = list.get(i);
            rows.add(p.split(line));
            System.out.println(i);
            //每次到70多W行,就内存溢出.咋办??
        }
        System.out.println(rows.size());



------解决方案--------------------
我试了一下,你这字符串100W行大约有70M,那么两个list,应该有100多M。

你看看你的jvm有多大?
------解决方案--------------------
你整个算法,因为全都是在List中,所以相当于永远也没法释放内存了,那么原始数据和拆分后的数据,都要完整保存在内存中。所以光靠更改切分方式是不可能降低内存开销的。

如果不能加大内存,就考虑另外两个方案:
1、借助文件做流式处理:把原始list先存在文件中,然后逐行读取,处理后的结果写入另一个文件中;这种做法内存开销最小,基本上就是几个字符串的开销而已。
2、边做边删:也就是在循环处理原始list的时候,把list的元素同时删除掉,做一笔就删除一笔。


强烈建议方式 1 !


方式2类似于:
int i = list.size()-1;
for( ;i >= 0; i--){
String line = list.get(i);
rows.add(p.split(line));
System.out.println(i);
list.remove(i); // 关键是这句话,这样原始的那行字符串就可以被释放了。
}

但是!!因为在你的例子里面,所有list的元素都是引用同一个 String s,所以在你的测试函数中,删除原始list记录,不能体现出回收内存的效果!

------解决方案--------------------
探讨

你整个算法,因为全都是在List中,所以相当于永远也没法释放内存了,那么原始数据和拆分后的数据,都要完整保存在内存中。所以光靠更改切分方式是不可能降低内存开销的。

如果不能加大内存,就考虑另外两个方案:
1、借助文件做流式处理:把原始list先存在文件中,然后逐行读取,处理后的结果写入另一个文件中;这种做法内存开销最小,基本上就是几个字符串的开销而已。
2、边做边删:也就是在循环处理原……