Java文件流关闭和垃圾回收机制

 更新时间:2016年07月06日 10:13:55   投稿:lqh  
本文是关于Java IO文件流和垃圾回收问题,一个小的测试程序搞清楚Java IO的问题,希望能帮助有需要的小伙伴

1.先看以下一段代码

import java.io.FileInputStream;
public class TTT {
	public static void main(String[] args) throws Exception {
		for (int i = 0; i < 10; i++) {
			final String threadId = "thread_" + i;
			Thread thread = new Thread(new Runnable() {
				public void run() {
					System.out.println(threadId + " started!");
					try {
						FileInputStream fis = new FileInputStream("/opt/test.log");
						Thread.sleep(60 * 1000);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
					System.out.println(threadId + " stopped!");
				}
			});
			thread.start();
		}
		Thread.sleep(10 * 60 * 1000);
	}
}

2.在linux上编译并运行这个类,然后使用linux的命令/usr/sbin/lsof -p <pid>来查看这个程序打开的文件信息

$ /usr/sbin/lsof -p `ps -ef | grep java | grep TTT | awk '{print $2}'` | grep "test.log"
java 21562 fkong 3r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 4r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 5r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 6r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 7r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 8r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 9r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 10r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 11r REG 253,0 0 35471424 /opt/test.log
java 21562 fkong 12r REG 253,0 0 35471424 /opt/test.log

不管是在10个线程运行过程中还是运行完,使用lsof命令查看的结果都一样,都可以看到有10个文件流没有关闭。

3.下面我把这个代码做了一些改动,就是在线程执行完之后,将所有线程置为null,如下

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
public class TTT {
	public static void main(String[] args) throws Exception {
		List<Thread> threads = new ArrayList<Thread>();
		for (int i = 0; i < 10; i++) {
			final String threadId = "thread_" + i;
			Thread thread = new Thread(new Runnable() {
				public void run() {
					System.out.println(threadId + " started!");
					try {
						FileInputStream fis = new FileInputStream("/opt/test.log");
						Thread.sleep(60 * 1000);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
					System.out.println(threadId + " stopped!");
				}
			});
			thread.start();
			threads.add(thread);
		}
		Thread.sleep(2 * 60 * 1000);
		for (Thread thread : threads) {
			thread = null;
		}
		System.out.println("Clean up threads!");
		Thread.sleep(10 * 60 * 1000);
	}
}
 

 

 




再次在10个线程运行过程中和运行完毕后使用lsof查看,结果仍然类似,还是有10个文件流没有关闭。

我再次做了一些改动,在将所有线程置为null以后,增加(或者说是催促JVM)做几次gc操作,如下:

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
public class TTT {
	public static void main(String[] args) throws Exception {
		List<Thread> threads = new ArrayList<Thread>();
		for (int i = 0; i < 10; i++) {
			final String threadId = "thread_" + i;
			Thread thread = new Thread(new Runnable() {
				public void run() {
					System.out.println(threadId + " started!");
					try {
						FileInputStream fis = new FileInputStream("/opt/test.log");
						Thread.sleep(60 * 1000);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
					System.out.println(threadId + " stopped!");
				}
			});
			thread.start();
			threads.add(thread);
		}
		Thread.sleep(2 * 60 * 1000);
		for (Thread thread : threads) {
			thread = null;
		}
		System.out.println("Clean up threads!");
		
		System.gc();
		System.gc();
		System.gc();
		System.out.println("Finished GC!");
		
		Thread.sleep(10 * 60 * 1000);
	}
}

再次使用lsof查看,在运行中仍然还是可以看到那有10个文件流打开着,但是在“Finished GC!”之后,看到的结果是那10个打开的文件流都被关闭了。

最后,我干脆把那些设置thread为null的语句删除了,运行的结果也和上面执行gc操作的结果一致。

最终,JVM中对于那些打开了没有关闭的IO文件流,会在不再被使用的情况下,等到下次做Full GC的时候把他们全部回收,但是让JVM去干这些事总归还是不好的,还是那句老话,自己的事情自己做。

相关文章

  • 全面解析JTA 深度历险

    全面解析JTA 深度历险

    本文介绍了利用 JTA 深度历险的相关内容,充分举例说明JTA的原理和事务处理等相关内容,十分详细,需要的朋友可以参考下。
    2017-09-09
  • SpringBoot学习系列之MyBatis Plus整合封装的实例详解

    SpringBoot学习系列之MyBatis Plus整合封装的实例详解

    MyBatis-Plus是一款MyBatis的增强工具(简称MP),为简化开发、提高效率,这篇文章给大家介绍MyBatis Plus整合封装的实例详解,感兴趣的朋友跟随小编一起看看吧
    2020-08-08
  • JAVA线上常见问题排查手段汇总

    JAVA线上常见问题排查手段汇总

    这篇文章主要介绍了JAVA线上常见问题排查手段汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Spring Boot详解五种实现跨域的方式

    Spring Boot详解五种实现跨域的方式

    跨域指的是浏览器不能执⾏其他⽹站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制,这篇文章主要介绍了springboot实现跨域的5种方式,需要的朋友可以参考下
    2022-06-06
  • java项目中classpath的理解

    java项目中classpath的理解

    这篇文章介绍了java项目中classpath的理解,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • SpringBoot应用能直接运行java -jar的原因分析

    SpringBoot应用能直接运行java -jar的原因分析

    这篇文章主要介绍了SpringBoot应用为什么能直接运行java -jar,首先明确一点,普通jar包是不能直接运行的,比如工具类jar,要能运行,至少得要一个main函数作为入口吧?本文给大家介绍了详细的原因分析,需要的朋友可以参考下
    2024-03-03
  • javacv视频抽帧的实现过程详解(附代码)

    javacv视频抽帧的实现过程详解(附代码)

    这篇文章主要介绍了javacv视频抽帧的实现过程详解(附代码),视频抽帧可以做一些处理,比如水印,去水印等操作,然后再合成视频,需要的朋友可以参考下
    2019-07-07
  • java  常见位逻辑运算符梳理

    java  常见位逻辑运算符梳理

    这篇文章主要介绍了java常见位逻辑运算符梳理,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参一下下面文章详细内容
    2022-08-08
  • Java中Spock框架Mock对象的方法经验总结

    Java中Spock框架Mock对象的方法经验总结

    这篇文章主要分享了Spock框架Mock对象的方法经验总结,下文分享一些常用项目实战说明以及代码,供大家项目中参考,也具有一的的参考价值,需要的小伙伴可以参考一下
    2022-02-02
  • Java中用Mybatis插入mysql报主键重复的解决方案

    Java中用Mybatis插入mysql报主键重复的解决方案

    这篇文章主要介绍了Java中用Mybatis插入mysql报主键重复的解决方案,具有很好的参考价值,希望对大家有所帮助。
    2023-02-02

最新评论