堆大小问题-使用java进行内存管理

堆大小问题-使用java进行内存管理,java,web-services,memory-management,Java,Web Services,Memory Management,我的应用程序中有以下代码,它完成两件事: 分析具有“n”个数据的文件 对于文件中的每个数据,将有两个web服务调用 public static List<String> parseFile(String fileName) { List<String> idList = new ArrayList<String>(); try { BufferedReader cfgFile = new BufferedReader(new FileR

我的应用程序中有以下代码,它完成两件事:

分析具有“n”个数据的文件

对于文件中的每个数据,将有两个web服务调用

 public static List<String> parseFile(String fileName) {
   List<String> idList = new ArrayList<String>();
   try {
     BufferedReader cfgFile = new BufferedReader(new FileReader(new File(fileName)));
     String line = null;
     cfgFile.readLine();
     while ((line = cfgFile.readLine()) != null) {
       if (!line.trim().equals("")) {
         String [] fields = line.split("\\|"); 
         idList.add(fields[0]);
       } 
     } 
     cfgFile.close();
   } catch (IOException e) {
     System.out.println(e+" Unexpected File IO Error.");
   }
 return idList;
}
公共静态列表解析文件(字符串文件名){
List idList=new ArrayList();
试一试{
BufferedReader cfgFile=新的BufferedReader(新文件读取器(新文件名));
字符串行=null;
cfgFile.readLine();
而((line=cfgFile.readLine())!=null){
如果(!line.trim()等于(“”){
String[]fields=line.split(“\\\\”);
idList.add(字段[0]);
} 
} 
cfgFile.close();
}捕获(IOE异常){
System.out.println(e+“意外的文件IO错误”);
}
返回懒汉;
}
当我尝试解析具有一百万行记录的文件时,java进程在处理了一定数量的数据后失败。我得到了
java.lang.OutOfMemoryError:java堆空间
错误。我可以部分地看出,java进程之所以停止,是因为提供了如此巨大的数据。请建议我如何处理这些庞大的数据


编辑:将这部分代码
新建BufferedReader(新文件阅读器(新文件名))解析整个文件并受文件大小的影响。

当您想要处理大数据时,有两种选择:

  • 使用足够大的堆来容纳所有数据。这将“工作”一段时间,但如果您的数据大小是无限的,它最终将失败
  • 以增量方式处理数据。在任何时候,只在内存中保留部分数据(大小有界)。这是理想的解决方案,因为它可以扩展到任何数据量

  • 问题是你正在积累列表上的所有数据。实现这一点的最佳方法是以流媒体方式进行。这意味着不要累积列表上的所有ID,而是在每一行上调用您的web服务,或者累积一个较小的缓冲区,然后进行调用

    打开文件并创建BufferedReader不会影响内存消耗,因为文件中的字节将逐行读取(或多或少)。问题就在代码
    idList.add(字段[0])中的这一点上,当您不断将所有文件数据累积到列表中时,列表将与文件一样大

    您的代码应该执行以下操作:

     while ((line = cfgFile.readLine()) != null) {
       if (!line.trim().equals("")) {
         String [] fields = line.split("\\|"); 
         callToRemoteWebService(fields[0]);
       } 
     } 
    

    使用-Xms和-Xmx选项增加java堆内存大小。如果没有显式设置,jvm会将堆大小设置为符合人体工程学的默认值,这在您的情况下是不够的。阅读本文了解有关jvm内存调优的更多信息:

    编辑:以生产者-消费者的方式利用并行处理的替代方法。一般的想法是创建一个生产者线程来读取文件,并将要处理的任务排队,然后创建n个消费者线程来使用它们。一个非常普遍的想法(为了说明目的)如下:

    // blocking queue holding the tasks to be executed
    final SynchronousQueue<Callable<String[]> queue = // ...
    
    // reads the file and submit tasks for processing
    final Runnable producer = new Runnable() {
      public void run() {
         BufferedReader in = null;
         try {
             in = new BufferedReader(new FileReader(new File(fileName)));
             String line = null;
             while ((line = file.readLine()) != null) {
                 if (!line.trim().equals("")) {
                     String[] fields = line.split("\\|"); 
                     // this will block if there are not available consumer threads to process it...
                     queue.put(new Callable<Void>() {
                         public Void call() {
                             process(fields);
                         }
                      });
                  } 
              }
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt());
         } finally {
             // close the buffered reader here...
         }
      }
    }
    
    // Consumes the tasks submitted from the producer. Consumers can be pooled
    // for parallel processing.
    final Runnable consumer = new Runnable() {
      public void run() {
        try {
            while (true) {
                // this method blocks if there are no items left for processing in the queue...
                Callable<Void> task = queue.take();
                taks.call();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
      }
    }
    
    //阻止包含要执行的任务的队列
    
    最终SynchronousQueueIMHO我认为第一个选项不是解决方案,因为我无法增加磁盘大小。目前我正在做第二个选项提到。感谢您的回复。:@Arun-是的,我试图澄清选项1并不是真正的解决方案。也就是说,我不确定磁盘大小与任何事情有什么关系…?对不起,我指的是我的prod box上java堆的大小,对此我没有权限…谢谢分享您的想法。但是我不满意我的代码。我可以从代码级别处理内存管理吗。另外,仅供参考,我确实有权更改我的生产框中设置的堆内存大小。确实,您的代码可以使用一些重构来提高内存利用率。其想法是,您可以考虑使用executor框架异步处理每个项目,而不是维护列表中的所有项目(从而更多地利用内存)。我会更新我的答案,告诉你怎么做。有没有办法找到堆的大小。。。我想在更改代码后监视堆大小。是。有两种方法可以确定堆的运行时大小。第一种方法是使用探查器(即)对应用程序进行评测,第二种方法是检查通过包含-XX:+PrintGCDetails jvm选项生成的垃圾收集输出。此选项输出每个主集合和次集合前后的堆大小。通过检查输出,您可以看到应用程序使用了多少堆大小,以及这些堆大小是如何在各代之间划分的。如果您不想使用gc输出或分析器,我知道的唯一其他方法是使用shell中的jmap命令。为了做到这一点,您首先必须通过发出jps命令来找出java应用程序的进程id(请参阅)。此命令将列出系统中当前运行的所有jvm进程ID。找到应用程序pid后,运行jmap-heap pid,其中pid是应用程序的进程id。(请参阅)