내부 클래스/정적 내부 클래스 스레드에서 GC(가비지 컬렉션)


- 내부 클래스 스레드에서 GC

: 내부 클래스는 외부 클래스의 멤버에 접근할 수 있다. 즉, 내부 클래스는 암시적으로 외부 클래스에 대한 참조를 가진다. 따라서 내부 클래스로 정의된 스레드는 스레드가 실행되는 동안 외부 클래스에 대한 참조를 유지하기 때문에 외부 클래스의 모든 객체는 스레드가 실행되는 한 내부 클래스와 함께 메모리에 있어야 한다. 익명 내부 클래스도 마찬가지다. 

public class Outer{
	public void sampleMethod(){
		SampleThread sampleThread = new SampleThread();
		sampleThread.start();
	}
	
	private class SampleThread extends Thread{
		public void run(){
			.....
		}
	}
}


- 정적 내부 클래스 스레드에서 GC

: 정적 내부 클래스는 외부 클래스의 정적 멤버가 아닌 멤버에 접근 못 한다. 외부 클래스 인스턴스 멤버이기 때문이다. 따라서 정적 내부 클래스로 정의된 스레드는 외부 객체 자체가 아닌 외부 객체 클래스(Outer.class)에 대한 참조만 유지한다. 즉, 외부 객체는 자신을 참조하는 다른 객체가 사라지면 가비지 컬렉션될 수 있다.

public class Outer{
	public void sampleMethod(){
		SampleThread sampleThread = new SampleThread();
		sampleThread.start();
	}
	private static class SampleThread extends Thread{
		public void run(){
			....
		}
	}
}

단 예외가 있다. 스레드를 생성할 때 Runnable 객체를 외부 클래스의 내부 클래스로 생성하면 Runnable객체가 외부 클래스에 대한 참조를 유지하게 된다. 이 때는 해당 스레드가 끝날 때 까지 외부 클래스 객체는 가비지 컬렉션이 되지 않는다. 다음은 그 예이다.

public class Outer{
	public void sampleMethod(){
		SampleThread sampleThread = new SampleThread(new Runnable() {
			
			@Override
			public void run() {
				...
			}
		})
	}
	private static class SampleThread extends Thread{
		public SampleThread(Runnable runnable){
			super(runnable);
		}
	}
	
}


이런 메모리 누수를 방지하는 방법으로는 정적 내부 클래스를 사용, 약한 참조 사용, 메시지 큐 정리 등이 있다. 이에 대해서는 "안드로이드 기본적인 메모리 누수 방지" 포스트에서 확인 바란다.

+ Recent posts