Java 파일 흐름 종료 및 쓰레기 수거 메커니즘

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 를 사용하여 이 프로그램에서 열린 파일 정보를 보십시오

$ /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!"그 후에 본 결과 열 개의 파일 흐름이 모두 닫혔다.
마지막으로, 나는 아예thread를null로 설정한 문장을 삭제했고, 실행 결과도 위에서 gc작업을 실행한 결과와 일치합니다.
결국 JVM에서 닫히지 않은 IO 파일 흐름을 열면 더 이상 사용되지 않는 상황에서 다음에 Full GC를 할 때 모두 회수하지만 JVM이 이런 일을 하게 하는 것은 아무래도 좋지 않다. 아니면 그 옛말, 자신의 일을 스스로 하는 것이다.

좋은 웹페이지 즐겨찾기