Java檔案流關閉和垃圾回收問題
阿新 • • 發佈:2018-11-16
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
週末碰到一段程式碼,是關於Java IO流的,程式碼中出現在一個多執行緒的系統中,其中一段程式碼在開啟一個檔案操作流用完以後沒有及時關閉,開始以為很快會出現開啟檔案太多或者導致記憶體溢位,但是在運行了很長時間以後仍然沒有出現問題,後來自己寫了個小程式測試了一下,總算似乎搞清楚為啥了。
先看以下一段程式碼
[java] view plain copy print ?- import java.io.FileInputStream;
- public class TTT {
- public static void main(String[] args) throws
- for (int i = 0; i < 10; i++) {
- final String threadId = "thread_"
- 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);
- }
- }
在linux上編譯並執行這個類,然後使用linux的命令/usr/sbin/lsof -p <pid>來檢視這個程式開啟的檔案資訊
[python] view plain copy print ?- $ /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個檔案流沒有關閉。
下面我把這個程式碼做了一些改動,就是線上程執行完之後,將所有執行緒置為null,如下
[java] view plain copy print ?- 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操作,如下:
[java] view plain copy print ?- 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去幹這些事總歸還是不好的,還是那句老話,自己的事情自己做。