Java中的多线程垃圾收集:在GC外部共享对象?
考虑以下方法:Java中的多线程垃圾收集:在GC外部共享对象?,java,multithreading,garbage-collection,Java,Multithreading,Garbage Collection,考虑以下方法: public void Parse(String[] S, Objects[] O) throws IOException { final int N_THREADS = Runtime.getRuntime().availableProcessors(); BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(20); RejectedEx
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();
}
公共void解析(字符串[]S,对象[]O)引发IOException{
final int N_THREADS=Runtime.getRuntime().availableProcessors();
BlockingQueue BlockingQueue=新阵列BlockingQueue(20);
RejectedExecutionHandler RejectedExecutionHandler=new ThreadPoolExecutor.CallerRunPolicy();
ThreadPoolExecutor服务=新的ThreadPoolExecutor(N_线程,N_线程,0L,TimeUnit.毫秒,blockingQueue,rejectedExecutionHandler);
最终SomeObject RO=新的SomeObject();
用于(字符串s:s){
service.execute(新的Runnable(){
公开募捐{
//初始化变量
用于(对象o:o){
V ps=适用(句子);
//更多关于ps的工作
}
文件f=新文件(“某物”);
FileWriter fw=null;
试一试{
fw=新文件编写器(f.getAbsoluteFile());
BufferedWriter bw=新的BufferedWriter(fw);
}捕获(IOE异常){
System.out.println(f.getAbsoluteFile());
}
BufferedWriter bw=新的BufferedWriter(fw);
for(句子注释条目:注释){
试一试{
write(entry.toString());
换行符();
}捕获(IOE异常){
e、 printStackTrace();
}
}
试一试{
bw.flush();
bw.close();
fw.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
});
}
service.shutdown();
而(!service.isTerminated()){
}
long-timeEnd=System.currentTimeMillis();
}
其中S是一个大数组(数十万),O的长度为50。我的问题是关于RO对象的。它是在外部创建的,如果您愿意,它将被所有线程“共享”。现在,当这段代码运行了一段时间后,堆空间就用完了,这让我感到困惑。我倾向于认为RO对象仍然保持其他已完成的Runnable活动,并慢慢消耗内存。这是真的吗?我已经使用“free-m”监控了linux系统(最新版本的OracleJDK)的内存消耗,我可以缓慢但肯定地看到内存消失。非常感谢您给我的建议。据我所知,您显示的代码没有任何可疑之处 最好的选择是获取应用程序的堆转储,然后检查内存中的内容 您可以使用jdk的
bin
文件夹中的JVisualVM生成堆转储并对其执行基本分析。例如,您肯定会发现许多关于堆分析的问题
在这段代码中,您正在泄漏一个未关闭的
BufferedWriter
。在try
子句的作用域中创建第一个,但不关闭它。引用消失,但运行时创建的任何本机句柄都不会被释放。您没有注意到这一点,因为您随后立即为同一文件创建了一个新的BufferedWriter
。您似乎创建了两次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对象。但不能保证
作为一个风格问题,我会考虑把“尝试”块组合成一个,使用一个“catch”而不是两个。当然,除非您打算给出不同的错误消息
希望有帮助
阿希姆
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();
}
}