考虑以下方法:
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)的内存消耗,我可以慢慢但肯定地看到内存消失了。我很感谢你能给我的任何建议。
答案 0 :(得分: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
。
答案 1 :(得分:0)
据我所知,您所展示的代码中没有任何可疑内容。
您最好的选择是获取应用程序的堆转储,然后检查填充内存的内容。
您可以使用 JVisualVM 生成堆转储并对其执行基本分析,该文件包含在您jdk的bin
文件夹中。关于堆分析,您肯定会发现很多关于堆的问题,例如How to find a Java Memory Leak。
答案 2 :(得分: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”而不是两个....除非你打算提供不同的错误信息,当然。
希望有所帮助。
Achim的