管理加载ZipFile时分配的内存

时间:2016-03-29 17:58:42

标签: java multithreading garbage-collection

我正在尝试将69,930个文件加载到基本文本编辑器中。这很顺利,在它们全部加载后,内存处于非常酷的130MB。但是,在峰值加载时间内,最高可达900MB - 1200MB。

内存全部引用Inflater#buf字段。这仅用于将文件加载到对象模型中,然后再也不会使用它,并且可以清除字节。

显然,额外的内存在加载后很快就被垃圾收集器清除了 - 所以没有内存泄漏。但是,似乎没有必要使用这么多额外的内存。

我尝试过:

  1. 在关闭System.gc()后立即拨打ZipFile来解决内存问题。这导致线程监视时间缩短约75%,CPU使用率高,加载时间慢。
  2. 减少线程池数。这减少了影响(达到300MB),但却导致显着更长的加载时间。
  3. WeakReference
  4. 到目前为止我所拥有的:

    Heap size analysis

    我通过一个4线程计数的线程池调用负载,每个线程池执行相对简单的任务:

    // Source source = ...;
    final InputStream input = source.open();
    
    // read into object model
    
    input.close();
    

    在这种情况下,SourceZipFileSource,可以完成所有阅读:

    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()调用,或者只是放弃并让它做它的事情。

    有没有办法可以在内存构建之前更有效地管理内存(需要垃圾回收调用)?

1 个答案:

答案 0 :(得分:0)

A)如果你的应用程序一直在运行,那么GC最终会在需要内存时收集这些对象。

B)如果您的应用程序在那时完成......那么......让VM死掉,它会将内存释放回操作系统。

无论哪种方式,都没有真正的记忆“浪费”。

垃圾收集者的意思是随着时间的推移分摊收集成本。它只能通过将它推迟到将来的某个点来实现,而不是像手动管理的语言那样立即尝试free()

另请注意,您的图表仅显示使用的堆(蓝色)下降。从操作系统的角度来看,已分配的堆(橙色)无论如何都保持不变,因此蓝色图表上的向下斜率不会为您带来任何好处。