java匿名文件流会自动关闭吗_java - 重用描述符的匿名文件流 - 堆栈内存溢出

以下代码块(每个代码块均相等)会导致意外错误吗? 我可以依靠行为,还是可以更改?

// 1st

FileOutputStream f = new FileOutputStream(...);

// some io, not shown

// 2nd

f = new FileOutputStream(f.getFD());

// some io, not shown

// 3rd

f = new FileOutputStream(f.getFD());

// some io, not shown

static FileOutputStream ExampleFunction(FileOutputStream fos) {

return new FileOutputStream(fos.getFD());

}

// |-- 3rd ------| |-- 2nd ------| |-- 1st ----------------|

ExampleFunction(ExampleFunction(ExampleFunction(new FileOutputStream(...))))

我之前概述了两种可能的结果。 我总是假设最糟糕的结果是,没有引用的对象将立即收集未引用的对象。 接下来是关于第一个代码块的。

情况1:

当第二个FileOutputStream分配给f ,第一个输出流将不再具有任何引用,因此将被收集。 完成后,基础文件描述符(在所有三个流之间共享)将被关闭。 此时,第二个FileOutputStream上的任何IO操作(未显示)都将引发IOException。 但是,第二个FileOutputStream保留对FileDescriptor的引用(现已关闭),以便第三个分配的RHS上的最后f.getFD()成功。 当第三个FileOutputStream分配给f ,将收集第二个输出流,并且底层FileDescriptor将再次关闭(我相信会生成IOException)。 但是,第三次流上的任何IO都会再次失败。

情况2:

另外,FileDescriptor保留对已分配给它的所有可关闭对象的强引用。 当将第二个FileOutputStream分配给f ,FileDescriptor维护对第一个FileOutputStream的引用,以便从不对其进行收集和终结,并且FileDescriptor保持打开状态。 当第三个FileOutputStream分配给f ,所有三个流都由描述符引用,并且不符合收集条件。

测试用例 :

我没有用于测试的JDK7,但显然适用案例1( JDK7 FileDescriptor.java ),除非未知的第三部分保存了引用或垃圾收集器做出了特定的豁免。

但是,JDK8显然更改了FileDescriptor来保存可关闭对象的列表,因此适用案例2( JDK8 FileDescriptor.java )。 我可以使用以下测试程序确认此行为(在openjdk8上):

import java.io.*;

import java.lang.ref.WeakReference;

import java.lang.Thread;

import java.lang.Runtime;

import java.lang.management.ManagementFactory;

import java.lang.management.OperatingSystemMXBean;

import com.sun.management.UnixOperatingSystemMXBean;

import java.util.ArrayList;

import java.util.Arrays;

class TestThread extends Thread {

static void gc() {

System.gc();

try {

sleep(1000);

}

catch (InterruptedException e) {

System.err.println(e.getMessage());

}

}

static void test(String message,

long fd_count_a,

ArrayList> fw,

OperatingSystemMXBean os,

FileDescriptor fd

) throws IOException {

long fd_count_b = fd_count_b = ((UnixOperatingSystemMXBean) os).getOpenFileDescriptorCount() - fd_count_a;

System.out.println("Results, " + message + ":");

for (int i=0; i

String prefix = "fw_" + String.valueOf(i);

if (fw.get(i).get() == null) {

System.out.println(prefix + ":\t\t" + "null");

System.out.println(prefix + " open" + ":\t" + "no");

} else {

System.out.println(prefix + ":\t\t" + fw.get(i).get().toString());

System.out.println(prefix + " open" + ":\t" + (fw.get(i).get().getFD().valid() ? "yes" : "no"));

}

}

System.out.println("fd :\t\t" + ((fd == null) ? "null" : fd.toString()));

System.out.println("fds :\t\t" + String.valueOf(fd_count_b));

System.out.println();

}

public void run() {

try {

run_contents();

}

catch (IOException e) {

System.err.println(e.getMessage());

}

}

public void run_contents() throws IOException {

FileOutputStream f = null;

WeakReference fw_1 = null;

WeakReference fw_2 = null;

WeakReference fw_3 = null;

FileDescriptor fd = null;

OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();

long fd_count_a = fd_count_a = ((UnixOperatingSystemMXBean) os).getOpenFileDescriptorCount();

f = new FileOutputStream("/dev/null");

fw_1 = new WeakReference(f);

f.write(1);

gc();

test("after fw_1", fd_count_a, new ArrayList>(Arrays.asList(fw_1)), os, f.getFD());

f = new FileOutputStream(f.getFD());

fw_2 = new WeakReference(f);

f.write(2);

gc();

test("after fw_2", fd_count_a, new ArrayList>(Arrays.asList(fw_1, fw_2)), os, f.getFD());

f = new FileOutputStream(f.getFD());

fw_3 = new WeakReference(f);

f.write(3);

gc();

test("after fw_3", fd_count_a, new ArrayList>(Arrays.asList(fw_1, fw_2, fw_3)), os, f.getFD());

f.close();

gc();

test("after closing stream", fd_count_a, new ArrayList>(Arrays.asList(fw_1, fw_2, fw_3)), os, f.getFD());

fd = f.getFD();

f = null;

gc();

test("after dereferencing stream", fd_count_a, new ArrayList>(Arrays.asList(fw_1, fw_2, fw_3)), os, fd);

fd = null;

gc();

test("after dereferencing descriptor", fd_count_a, new ArrayList>(Arrays.asList(fw_1, fw_2, fw_3)), os, fd);

}

}

class Test {

public static void main(String[] args) {

TestThread t = new TestThread();

t.start();

try {

t.join();

}

catch (InterruptedException e) {

System.err.println(e.getMessage());

}

}

}

具有以下输出:

Results, after fw_1:

fw_0: java.io.FileOutputStream@7afd6488

fw_0 open: yes

fd : java.io.FileDescriptor@743a95a7

fds : 1

Results, after fw_2:

fw_0: java.io.FileOutputStream@7afd6488

fw_0 open: yes

fw_1: java.io.FileOutputStream@70050ff8

fw_1 open: yes

fd : java.io.FileDescriptor@743a95a7

fds : 1

Results, after fw_3:

fw_0: java.io.FileOutputStream@7afd6488

fw_0 open: yes

fw_1: java.io.FileOutputStream@70050ff8

fw_1 open: yes

fw_2: java.io.FileOutputStream@35079f9c

fw_2 open: yes

fd : java.io.FileDescriptor@743a95a7

fds : 1

Results, after closing stream:

fw_0: java.io.FileOutputStream@7afd6488

fw_0 open: no

fw_1: java.io.FileOutputStream@70050ff8

fw_1 open: no

fw_2: java.io.FileOutputStream@35079f9c

fw_2 open: no

fd : java.io.FileDescriptor@743a95a7

fds : 0

Results, after dereferencing stream:

fw_0: java.io.FileOutputStream@7afd6488

fw_0 open: no

fw_1: java.io.FileOutputStream@70050ff8

fw_1 open: no

fw_2: java.io.FileOutputStream@35079f9c

fw_2 open: no

fd : java.io.FileDescriptor@743a95a7

fds : 0

Results, after dereferencing descriptor:

fw_0: null

fw_0 open: no

fw_1: null

fw_1 open: no

fw_2: null

fw_2 open: no

fd : null

fds : 0

但是,根据此错误报告 (似乎后来有人撤消并推迟了该报告) ,似乎有所推动,以防止FileDescriptor保持对可关闭对象的强引用。

所以,我的问题是:

我对JDK7的假设是否正确-它的行为与JDK8不同?

我是否可以依靠JDK8的FileDescriptor的行为来保持对可闭合对象的强引用,或者在以后的JDK版本中将其还原?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值