各位大侠,我编写了一个分析文本文件的小程序,用来分析某个文件夹中2000多个文本文件(每个文件大概在1000行,每行7数据,用";"隔开,每行第一个数据是索引),我要遍历所有文件,找出所有满足以下条件的文件名:
1.存在指定的索引值
2.索引对应的行的第6个数据的值是上一行的第6个数据的一半。
我的代码如下:(能分析成功,但jvm空闲内存会不断下降,直到耗光,不知道何原因,求大家帮忙分析一下,在线等)
FileRead.java
public class FileRead {
private File f;
private String basepath;//路径
public FileRead(String basepath){
this.basepath=basepath;
}
public  String[] getFilenames(){
f =new File(basepath);
return f.list();
}
public  String read(String filename) {
String content = "";
    if (filename != null && filename.length() != 0) {
      File f = new File(basepath+"/"+filename);
      char buffer[] = new char[4096];
      try {
        FileReader in = new FileReader(f);
        while (true) {
          int length = in.read(buffer);
          if (length != -1) {
            content = content.concat(new String(buffer).substring(0,length));
          }else break;
        }
        in.close();
        return content;
      }
      catch (IOException e) {
        System.out.println(e.getMessage());
      } 
    }
    return null;
}}
2. Analyse.java
public class Analyse {
 List<String> half=new ArrayList<String>();
          public void analyseHalf(String basepath,String index){
                FileRead fr=new FileRead(basepath);
       //获取文件列表
                String [] flist=fr.getFilenames();
       //开始遍历
                for(int i=0;i<flist.length;i++){
                     String buffer = fr.read(flist[i]);//读取文件
   String [] line=buffer.split("\n");//分解成行
                     buffer=null;
if(line.length<4){
continue;//小于4行的忽略
}
// 寻找索引
int beginning=line.length-1;
String today[]=null;
for(;beginning>2;beginning--){
today=line[beginning].split(";");//分解成7个数据
if(index.equals(today[0]))
break;
}
String yesterday[]=line[beginning-1].split(";");
if(Integer.parseInt(yesterday[5])>Integer.parseInt(today[5])*2){
half.add(flist[i]);
}
}
}
}

解决方案 »

  1.   

    FileRead 未关闭.是这个原因么
      

  2.   

    能分析成功,但jvm空闲内存会不断下降,直到耗光,不知道何原因,求大家帮忙分析一下  既然已经分析成功了,程序就退出了,何来内存溢出问题???lz写的情况有点简单啊
      

  3.   

    我们做weblogic发布时会遇到loadclass的函数没有及时回收,只能调整参数来拯救!
      

  4.   

    我用rumtime.freeMemery监控了每读一个文件后耗的内存,将文件按行分解成数组后的内存消耗,以及list.add 后的内存消耗,发现开始的时候freeMemery的值会上下波动并趋于下降,就是说内存在消耗、回收,但消耗比回收快得多。
    另外随着传进来的index值不同,结果也会不一样,这就出现了有时候程序能正常退出,有时候会内存溢出
      

  5.   

    这个很正常,你仔细看看你的程序,新建的String很多,例如:
    while (true) {
    int length = in.read(buffer);
    if (length != -1) {
    content = content.concat(new String(buffer).substring(0,length));
    不要忘记了,String的底层是数组,concat的底层也是申请一个更大的数组来存储而已。
    new String(buffer) 这也是,在String的内部申请了数组,然后把buffer复制过去而已。
    而且这句话事在循环体里,肯定有很多new了很多String的对象了,每一个 String 对象都得独立占用内存一块区域。Eden区放不下这些对象。或者有些无用的对象gc不能回收!还有报错的信息你也没有贴出来!
      

  6.   

    楼主 我对你这个问题 很感兴趣。 我也做过很多解析文件的程序。
        不知道你 所谓的 程序解析成功了 就是程序代码跑完了 结果你的JVM 还在吃内存。
      是不是你用的线程定时在包程序。还是你在外面调用的时候 写了个 死循环还是怎么 。怎么条用这个
    解析部分代码的方式 说清楚点。还有你如果用 content = content.concat(new String(buffer).substring(0,length)); 这个 用Stringbuffer 的话 会不会好点。对你运行过程中 声明对象少。应该会少占点内存。 但是 你说程序解析完了还在吃内存。这个问题 应该跟这个 没有多大关系。
      

  7.   

    我用rumtime.freeMemery监控了每读一个文件后耗的内存,将文件按行分解成数组后的内存消耗,以及list.add 后的内存消耗,发现开始的时候freeMemery的值会上下波动并趋于下降,就是说内存在消耗、回收,但消耗比回收快得多。
    另外随着传进来的index值不同,结果也会不一样,这就出现了有时候程序能正常退出,有时候会内存溢出
    这是他的解释!题目描述得有误
      

  8.   

    估计是在下面的代码!我猜想你的jdk是client端的,默认的堆分配?内存2G???
      

  9.   

    你误解了,不管是否提示内存溢出错误(当然如果侥幸还有一点点内存,程序能正常结束),我监控到的整个分析过程内存是不断在消耗的,如果最后剩下的内存不够再读入一个文件时就报错内存溢出。
    另外StringBuffer我试过,效果一样的
      

  10.   

    你说的我也怀疑过,但怎么解决呢?怎么能让gc及时回收无用空间呢?我曾怀疑读入内存的String对象和数组一直被引用,但没看出问题所在
    报错是在读入文件的时候内存溢出,当然不是第一个文件啦,估计在读过1000多个文件时报错的,那些英文就不贴出来了,大家都熟悉的
      

  11.   

    60KB  2000 多个也不大的。
       
        我想问问  LZ  你的文件 是不是有特别大的。只是你不知道的呢?
      我以前遇到过这样的一个问题
      就是在解析文件 的时候 有个文件特别大我解析后 stringbuffer.toString() 的时候 就报错了。
     
      

  12.   

    不会的,按大小排过序,最大才60多k,而且曾怀疑过文件有问题,把报错的那个文件删除同样会在读今后的几个文件时报错这么说,大家都不认为是程序在循环过程中可能存在某些对象(尤其是buffer)被强引用而不能被释放了?我郁闷就是怀疑这点,如果程序没问题,而是确实是gc来不及回收的原因的话,那我就结贴了。
      

  13.   

     这个 应该不能这么早下决定。。  JAVA 这个 满深的 我们好好研究下吧。
        
              我觉得不能。  我做过解析 每个文件   13M 到 19M  不等总共有 24个文件解析。。 也是要找到里面我需要的东西。 在把我需要的东西入库。
          起初报错的原因是  读取15M 文件的时候 stringbuffer.toString()报错。后来用了文件映射内存的方式做的。
        我对你这个问题真的很感兴趣。如果可以的话 我想试试。
      

  14.   


    就是这个问题,java的gc不能保证在对象没有引用后的立即释放。
    所以即使有时你的流关闭了,可能jvm的内存还是被占用着。gc在执行的时间上,是不可控的,即使你调用,也不是立即回收。
      

  15.   

    String content = "";
    ...
    while (true) {
    int length = in.read(buffer);
    if (length != -1) {
    content = content.concat(new String(buffer).substring(0,length));
    }else break;
    }----------------------------------------------------------------
    content 改为StringBuffer类型
    StringBuffer content = new StringBuffer();
    ...
    while (true) {
    if (in.read(buffer) != -1) {
    content.append(buffer);
    }else break;
    }
    ===============================================================
    //开始遍历
      for(int i=0;i<flist.length;i++){----------------------------------------
    for(int i = 0 , len = flist.length ; i < len ; i++)
      

  16.   

    使用JDK自带的Jconsole命令查看下是不是有java虚拟机内存泄露现象,
    如果你的电脑装了JDK的话,直接在Dos下打命令"Jconsole",然后就可以查看是否有java虚拟机的内存泄露..
      

  17.   

    to.String的时再申请了一个大数组(你看底层),你stringbuffer那么大,当然Eden不够内存了!
      

  18.   

    new了那么多的字符数组出来。好恐怖!多给JVM分配点内存试试吧。
      

  19.   

    谢谢指出,确实漏了一段
    // 如果找不到index,结束分析
    if(beginning<=2) {
    line=null;
    continue;
    }
      

  20.   

    楼主干嘛要自己写那么大段代码来实现按行读取呢?JDK有自带的API啊,
    试试用这个:String line = null;
    BufferedReader reader = new BufferedReader(new FileReader(file));
    line = reader.readLine();也许真的是你new了太多的临时String对象,导致GC回收速度跟不上。
      

  21.   

    我觉得30楼是一个原因
    另外一个为什么要把一个文件read成一个大字符串再split?
    个人认为split比较耗费资源,包括CPU和内存,尤其是字符串比较大的情况建议用BufferedReader一次读进来一行再分析:
    BufferedReader br = new BufferedReader(new FileReader(new File(filename)));
    String line = br.readLine();
    while(line!=null) {
      analyze(line);
    line = br.readLine();
    }
      

  22.   

    很多朋友都说new太多string了,这是有道理的。
    content = content.concat(new String(buffer).substring(0,length));这段百分之百是煞笔。你每次都将为string新辟一段内存,必须优化为stringbuffer。
    如:
    string a = "a";       //值为a,内存地址指到A
    a = a + "b";          //值为ab,内存地址指到B
    a = a + "c";          //值为abc,内存指到C
    你无限期的合并,那么将有无限内存被浪费,gc回收速度决对跟不上。因为你的文件多,很多对象被创建了,虽然占用不大,但你2k或更多文件的积压就无法想象,所以建议在一个循环结束时把你创建的对象都释放或设置为null,以减少gc的判断,然后再执行回收。
      

  23.   

    LZ 你这个问题 我从新写了一遍。
        那你的方法我自己写了。 没有出现你的问题。
        有时间 你上QQ 我们聊下。
      

  24.   

    我只看了你的需求,没有看你的代码,这样的程序很简单,处理
    File filepath = new File(pathName); //pathName 对应路径
    if (filepath.exists()) {
    File[] files = filepath.listFiles();
    for (File file : files) {
                                   FileInputStream input = null;
                                   input = new FileInputStream(file);
                                    //处理逻辑
                                   input.close(); //一定要及时关闭
                                   //如果最后一行和下一个文件有关系的话,把最后一行的数据保存到一个                      String中去即可
                             }以上逻辑占用的内存很小
      

  25.   

    什么呀?
    这个程序和GC有很大的关系吗?
    数据量那么点,造你们这么一说 那处理千万级的数据都不能用java了吧...楼主把需求说的详细的,我写写..看你的需求还是挺有意思的
      

  26.   

    关键是楼主的代码创建了过多的对象以及过大的对象。而这些对象有应用的话是不会被GC回收的,时间长了当然JVM内存会上升了。
      

  27.   

    lz我用工具分析过了,运行你的 程序,堆内存最大也就是1600KB左右!不会超过2M!没有内存溢出问题!
    我的机器是2G!