0

考虑以下方法:

public void Parse(String[] S, Objects[] O) throws IOException {
    final int N_THREADS = Runtime.getRuntime().availableProcessors();
    BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(20);
    RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
    ThreadPoolExecutor service =  new ThreadPoolExecutor(N_THREADS, N_THREADS, 0L, TimeUnit.MILLISECONDS, blockingQueue, rejectedExecutionHandler);
    final SomeObject RO = new SomeObject();
    for(String s : S){
        service.execute(new Runnable() {
            public void run() {
                // initialize variables
                for (Object o : O) {
                        V ps = RO.apply(sentence);
                        //more work on ps 
                }
                File f = new File("something");
                FileWriter fw = null;
                try {
                    fw = new FileWriter(f.getAbsoluteFile());
                    BufferedWriter bw = new BufferedWriter(fw);
                } catch (IOException e) {
                    System.out.println(f.getAbsoluteFile());
                }
                BufferedWriter bw = new BufferedWriter(fw);
                for (SentenceAnnotation entry : annotations) {
                    try {
                        bw.write(entry.toString());
                        bw.newLine();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                try {
                    bw.flush();
                    bw.close();
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
    service.shutdown();
    while (!service.isTerminated()) {
    }
    long timeEnd = System.currentTimeMillis();
}

其中 S 是一个大数组(数十万),O 的长度为 50。我的问题是关于 RO 对象。如果您愿意,它是在外部创建并由所有线程“共享”的。现在,当这段代码运行一段时间后,堆空间耗尽,这让我感到困惑。我倾向于认为 RO 对象仍然使原本已完成的 Runnables 保持活力并慢慢消耗内存。真的吗?我已经使用“free -m”监控了 linux 系统(最新版本的 Oracle JDK)的内存消耗,我可以缓慢但肯定地看到内存消失。我很感谢你能给我的任何建议。

4

3 回答 3

1
 try {
   fw = new FileWriter(f.getAbsoluteFile());
   BufferedWriter bw = new BufferedWriter(fw);
 } catch (IOException e) {
   System.out.println(f.getAbsoluteFile());
 }
 BufferedWriter bw = new BufferedWriter(fw);

BufferedWriter在这部分代码中泄漏了一个未封闭的内容。您在子句的范围内创建第一个try,而不是关闭它。引用消失了,但运行时创建的任何本机句柄都不会被释放。您不会注意到,因为您BufferedWriter随后立即为同一文件创建了一个新文件。

于 2013-10-24T20:52:28.797 回答
0

据我所知,您显示的代码中没有任何可疑之处。

您最好的选择是获取应用程序的堆转储,然后检查填充内存的内容。

您可以使用jdk 文件夹中包含的JVisualVM 生成堆转储并对其执行基本分析。bin您肯定会在 SO 上找到许多关于堆分析的问题,例如How to find a Java Memory Leak

于 2013-10-24T20:47:52.400 回答
0

您似乎两次创建了 BufferedWriter 。我不太确定这里的范围问题,但在我看来,这甚至不应该正确编译。尝试在“try”块之前声明 BufferedWriter 并简单地使用它而无需第二次创建:

        BufferedWriter bw;            
        try {
            fw = new FileWriter(f.getAbsoluteFile());
            bw = new BufferedWriter(fw);
        } catch (IOException e) {
            System.out.println(f.getAbsoluteFile());
        }
        for (SentenceAnnotation entry : annotations) {
            try {
                bw.write(entry.toString());
                bw.newLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

如果我是对的,那么您将不会生成“数十万”个不必要的 BufferedWriter 对象。不过,没有保证。

作为一个风格问题,我会考虑将“try”块合并为一个,并使用一个“catch”而不是两个....当然,除非您打算给出不同的错误消息。

希望有帮助。

阿奇姆

于 2013-10-24T21:12:06.363 回答