为什么Java的InflaterInputStream(和其他类似的类)仅在其内部Inflater上有条件地调用end

con*_*fin 6 java memory heap native

在Java 8中,close()方法InflaterInputStream如下所示

public void close() throws IOException {
    if (!closed) {
        if (usesDefaultInflater)
            inf.end();
        in.close();
        closed = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

usesDefaultInflater是一个布尔值,仅true当使用以下构造函数时

public InflaterInputStream(InputStream in) {
    this(in, new Inflater());
    usesDefaultInflater = true;
}
Run Code Online (Sandbox Code Playgroud)

诸如此类的其他任何构造函数都会导致此布尔值设置为false

new InflaterInputStream(decryptInputStream, new Inflater(), 4096);
Run Code Online (Sandbox Code Playgroud)

因此,除非使用默认的构造函数,否则end()不会在上调用该方法Inflater,这意味着不必要的本机内存消耗,直到终结器线程可能在关闭了很长一段时间后才在Finalizer线程finalize上调用该方法。请参阅下面的实现。InflaterInflaterInputStreamInflater

/**
 * Closes the decompressor and discards any unprocessed input.
 * This method should be called when the decompressor is no longer
 * being used, but will also be called automatically by the finalize()
 * method. Once this method is called, the behavior of the Inflater
 * object is undefined.
 */
public void end() {
    synchronized (zsRef) {
        long addr = zsRef.address();
        zsRef.clear();
        if (addr != 0) {
            end(addr);
            buf = null;
        }
    }
}

/**
 * Closes the decompressor when garbage is collected.
 */
protected void finalize() {
    end();
}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,您需要重写类似的close方法,InflaterInputStream这样

new InflaterInputStream(decryptInputStream, new Inflater(), 4096) {    
    @Override
    public void close() throws IOException {
        try {
            super.close();
        } finally {
            inf.end();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是很容易错过,它似乎对我来说,它可能是明智调用end()默认情况下,允许用户通过提供一个构造函数,你可以指定替代该行为false,或者至少是一个构造函数,使用默认Inflater但也允许您设置缓冲区大小。

无论如何,我猜测它是按原样设计的,这是有逻辑的,而我只是未能理解它。希望有人能启发我...

这也适用于DeflaterInputStreamDeflaterOutputStreamInflaterOutputStream在其他之中。

And*_*eas 4

Java 运行时库中有许多方法采用例如 an OutputStream(例如Files.copy())。除非这些方法明确声明该方法将关闭该流,否则该流将不会被关闭。关闭流是流“所有者”(例如方法的调用者)的责任。

类似地,InflaterInputStream它的构造函数都没有Inflater声明它们将end()Inflater这意味着它们不会。当需要时,由调用者决定结束它。

Inflater当使用为您创建 的构造函数时, 成为该内部InflaterInputStream的“所有者” ,因此结束的责任是。 InflaterInflaterInputStreamInflater

资源管理

资源管理的一般准则是,除非另有说明,分配资源的人负责释放(关闭、结束……)资源。

Inflater是一种资源,因此适用正常的资源管理规则。