익명클래스의 메모리 누수

2021-12-11

익명 클래스의 메모리 누수

자바의 익명 클래스는 유용하지만 사용할 때 주의 해야 한다.

inner 클래스의 인스턴스가 outer 클래스보다 더 오래 생존하는 경우 메모리 누수가 일어난다.

그 이유는 inner 클래스가 outer 클래스의 참조를 유지하기 때문이다.

테스트 시나리오

HashSet 클래스에 원소를 두개 넣는 예제로 테스트 해보자.

  • 테스트 1은 익명클래스를 사용하지 않고 테스트를 한다.
  • 테스트 2는 익명클래스를 사용하고 테스트를 한다.
  • 테스트 1와 테스트 2의 메모리 사용량을 비교한다.
public class Main {
    
    public static void main(String[] args) throws IOException {

        List<Set> stringList = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Generator gen = new Generator();
            // 익명 클래스 사용하지 않고 테스트
            stringList.add(gen.createStringsNormally());
            // 익명 클래스 사용한 테스트
//            stringList.add(gen.createStringsInnerClass());
        }
        
        System.out.print("press Enter to continue:");
        System.in.read();
    }

    public static class Generator {

        //10MB 공간 생성
        private byte[] lotsOfHiddenStuff = new byte[10_000_000];

        public Set createStringsInnerClass() {
            Set strings = new HashSet() ;
            return strings;
        }

        public Set createStringsNormally() {
            Set strings = new HashSet();
            strings.add("a");
            strings.add("b");
            return strings;
        }
    }
}

테스트 결과

익명클래스 사용 안함

이미지내용

익명클래스 사용함

이미지내용

익명 클래스는 외부 클래스의 참조를 유지를 한다.

외부 클래스인 Generator 클래스는 생성될 때마다 lotsOfHiddenStuff 변수의 크기인 10MB 만큼 메모리를 사용한다.

for 문을 100번 돌렸으니 1000MB인 1GB를 사용하게 된다.

하지만 익명클래스의 특징 때문에 외부 클래스인 Generator 클래스의 참조를 계속 물고 다니기 때문에

가비지컬렉션의 대상이 아니기 때문에 메모리 누수가 생기게 된다.

정리

익명클래스를 사용을 자제하자.

또한 익명클래스가 아닌, non-static inner 클래스에도 해당하는 내용이므로,

메모리 누수가 일어나지 않도록 신경을 쓰자.

static inner 클래스는 괜찮다.