转载自: https://blog.csdn.net/tugangkai/article/details/79593495
gc回收对象时关闭相关的流
一、代码
1、FileOperation
public class FileOperation {
private FileOutputStream outputStream;
private FileInputStream inputStream;
public FileOperation(FileInputStream inputStream, FileOutputStream outputStream) {
this.outputStream = outputStream;
this.inputStream = inputStream;
}
public void operate() {
try {
inputStream.getChannel().transferTo(0, inputStream.getChannel().size(), outputStream.getChannel());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、ResourcePhantomReference
public class ResourcePhantomReference<T> extends PhantomReference<T> {
private List<Closeable> closeables;
public ResourcePhantomReference(T referent, ReferenceQueue<? super T> q, List<Closeable> resource) {
super(referent, q);
closeables = resource;
}
public void cleanUp() {
if (closeables == null || closeables.size() == 0)
return;
for (Closeable closeable : closeables) {
try {
closeable.close();
System.out.println("clean up:"+closeable);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3、ResourceCloseDeamon
public class ResourceCloseDeamon extends Thread {
private static ReferenceQueue QUEUE = new ReferenceQueue();
//保持对reference的引用,防止reference本身被回收
private static List<Reference> references=new ArrayList<>();
@Override
public void run() {
this.setName("ResourceCloseDeamon");
while (true) {
try {
System.out.println("开始运行.....");
//remove是阻塞方法,会一直等到可以获取到元素
ResourcePhantomReference reference = (ResourcePhantomReference) QUEUE.remove();
reference.cleanUp();
references.remove(reference);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void register(Object referent, List<Closeable> closeables) {
references.add(new ResourcePhantomReference(referent,QUEUE,closeables));
}
}
4、测试类
public class PhantomTest {
public static void main(String[] args) throws Exception {
//打开回收
ResourceCloseDeamon deamon = new ResourceCloseDeamon();
deamon.setDaemon(true);
deamon.start();
// touch a.txt b.txt
// echo “hello” > a.txt
//保留对象,防止gc把stream回收掉,其不到演示效果
List<Closeable> all=new ArrayList<>();
FileInputStream inputStream;
FileOutputStream outputStream;
for (int i = 0; i < 100000; i++) {
inputStream = new FileInputStream("/Users/robin/a.txt");
outputStream = new FileOutputStream("/Users/robin/b.txt");
FileOperation operation = new FileOperation(inputStream, outputStream);
operation.operate();
TimeUnit.MILLISECONDS.sleep(100);
List<Closeable> closeables=new ArrayList<>();
closeables.add(inputStream);
closeables.add(outputStream);
all.addAll(closeables);
/**
* 虚引用中被引用的对象(此例指的是operation对象)什么时候被回收?
* 在下次循环的时候,会被回收
* operation对象在本次循环中还有强引用,不会被回收
* 下次循环的时候,因为operation是局部变量,会消失,就没有了强引用。
* 这个时候就只有虚引用,发生gc就会被gc回收掉。
*/
ResourceCloseDeamon.register(operation,closeables);
//用下面命令查看文件句柄,如果把上面register注释掉,就会发现句柄数量不断上升
/**
* 所以创建在堆中的对象(operation)会不断的被回收,堆中的使用率不会大幅度上升。
*/
//jps | grep PhantomTest | awk ‘{print $1}’ |head -1 | xargs lsof -p | grep /User/robin
System.gc();
}
}
}