我正在尝试将69,930个文件加载到基本文本编辑器中。这很顺利,在它们全部加载后,内存处于非常酷的130MB。但是,在峰值加载时间内,最高可达900MB - 1200MB。
内存全部引用Inflater#buf
字段。这仅用于将文件加载到对象模型中,然后再也不会使用它,并且可以清除字节。
显然,额外的内存在加载后很快就被垃圾收集器清除了 - 所以没有内存泄漏。但是,似乎没有必要使用这么多额外的内存。
System.gc()
后立即拨打ZipFile
来解决内存问题。这导致线程监视时间缩短约75%,CPU使用率高,加载时间慢。我通过一个4线程计数的线程池调用负载,每个线程池执行相对简单的任务:
// Source source = ...;
final InputStream input = source.open();
// read into object model
input.close();
在这种情况下,Source
是ZipFileSource
,可以完成所有阅读:
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ZipFileSource implements Source {
private final String file;
private final String name;
private volatile ZipFile zip;
public ZipFileSource(final String file, final String name) {
this.file = file;
this.name = name;
}
@Override
public InputStream open() throws IOException {
close();
final ZipFile zipFile = new ZipFile(file);
final ZipEntry entry = zipFile.getEntry(name);
final InputStream stream = new ZipFileSourceZipInputStream(zipFile.getInputStream(entry));
this.zip = zipFile;
return stream;
}
@Override
public void close() throws IOException {
if (zip != null) {
zip.close();
zip = null;
}
}
private class ZipFileSourceZipInputStream extends InputStream {
private final InputStream stream;
ZipFileSourceZipInputStream(final InputStream stream) {
this.stream = stream;
}
@Override
public int read() throws IOException {
return stream.read();
}
@Override
public void close() throws IOException {
ZipFileSource.this.close();
stream.close();
}
}
}
我的想法很缺乏。我已经使用原生的zip提取器,锁定每个n
个请求进行System.gc()
调用,或者只是放弃并让它做它的事情。
答案 0 :(得分:0)
A)如果你的应用程序一直在运行,那么GC最终会在需要内存时收集这些对象。
B)如果您的应用程序在那时完成......那么......让VM死掉,它会将内存释放回操作系统。
无论哪种方式,都没有真正的记忆“浪费”。
垃圾收集者的意思是随着时间的推移分摊收集成本。它只能通过将它推迟到将来的某个点来实现,而不是像手动管理的语言那样立即尝试free()
。
另请注意,您的图表仅显示使用的堆(蓝色)下降。从操作系统的角度来看,已分配的堆(橙色)无论如何都保持不变,因此蓝色图表上的向下斜率不会为您带来任何好处。