본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[Design Pattern/Java] 쓸모 없는 객체 참조를 제거하자.

by 돼지왕 왕돼지 2012. 2. 10.
반응형


안녕하세요 돼지왕왕돼지입니다.
오늘은 쓸모 없는 객체 참조를 제거하자. 라는 주제로 이야기하고자 합니다.
이 글은 "Effective Java" 를 기반으로 작성되었습니다.


자바의 GC는 만능이 아니다.


- 자바와 같이 가비지 컬렉션 ( Garbage Collection 이하 G.C. ) 을 자동으로 해주는 언어는 G.C.가 더 이상 참조되지 않는 객체들의 메모리를 자동으로 회수합니다. 그래서 자칫하면 우리가 메모리 관리를 고려하지 않아도 된다는 생각을 가질 수 있으나, 그것은 사실이 아닙니다.


2012/01/12 - [프로그래밍 놀이터/자바] - [Java] Garbage Collection ( GC ) 가 뭐 하는 녀석인지 한 번 해부해보자. 




메모리 누출 ( Memory Leak ).


- 메모리 누출은 잦은 GC의 호출로 이어질 수 있고, 이는 빈번한 메모리 할당과 회수를 야기하기 때문에 성능 저하로 이어질 수 있습니다.

- 최악의 경우에는 디스크상의 페이징( paging ) 현상( Virtual Memory 를 사용한다는 의미이겠죠. ) 이 생길 수도 있고, OutOfMemoryError로 인해 프로그램이 중단될수도 있습니다.

- Memory Leak 은 쓸모 없는 참조를 가지고 있기 때문에 자주 발생합니다. 여기서 쓸모 없는 참조란, 객체에 대한 참조 값( null 이 아닌 ) 을 가지고 있지만, 다시는 사용되지 않을 참조를 말합니다.

- 의도하지 않은 객체 유지 ( unintentional object retention ) 인 Memory Leak 은 보통 우리가 모르는 사이 진행되며, 만일 G.C. 되어야할 특정 객체의 참조가 의도하지 않게 계속 유지된다면, 그 객체는 물론이고 그 객체가 참조하는 모든 다른 객체까지도 G.C. 대상에서 제외됩니다. 단지 몇개의 객체 참조만 의도하지 않게 유지되어도 수없이 많은 객체들이 영향을 받을 수 있습니다.



Memory Leak 의 해결책


- 가장 쉬운 방법은 쓸모 없는 참조를 null 로 만듭니다. 이 방법은 추가적 장점이 있는데, 그런 참조들이 나중에 실수로 사용되었을 때 NullPointerException 이 생겨 엉뚱한 실행을 예방할 수 있습니다. 단, 코드 실행이 끝나는 즉시 지나치게 모든 객체 참조를 null 로 바꾸려 한다면, 코드의 가독성이 떨어지기 쉽습니다. 따라서 객체 참조를 null 로 변경하는 것은 꼭 필요할 때만 예외적으로 수행하는 것이 좋습니다.

- 가장 좋은 방법은 참조 값을 갖는 변수가 최소한의 유효 범위 안에 있도록 하는 것이다. Local 변수로 만든다던지.. 그러면 자동으로 G.C. 대상이 됩니다.


[ Memory Leak Code Example ]

private Object[] elements;
private int size = 0;

public Object pop(){
   if ( size == 0 )
      throw new EmptyStackException();
   return elements[ -- size ];
}

 

[ Memory Leak Resolved Code Example ]

private Object[] elements;
private int size = 0;

public Object pop(){
   if ( size == 0 )
      throw new EmptyStackException();
   Object result = elements[ -- size ];
   elements[ size ] = null;
   return result;
}

 



Memory Leak 의 주된 이유


1. 프로그래머가 자신의 메모리를 스스로 관리하려 하기 때문.


- 특정 요소가 더 이상 사용이 되지 않는 것이 확실하다면 해당 객체 참조를 반드시 null 값으로 변경하는 것이 좋습니다.


2. 캐시 ( Cache ) 의 사용


- 객체 참조를 캐시에 저장하면 저장한 것을 잊어 버리고 객체가 더 이상 필요 없을 때에도 캐시에 내버려두기 쉽습니다.
- 쉬운 해결책은 캐시 외부에 캐시의 키( key )에 대한 참조가 있을 동안만 유효한 캐시를 구현하는 것인데, WeakHashMap 를 사용하면 쉽습니다.
- 캐시에 저장된 항목의 생명주기가 잘 정의되지 않습니다. 잊어버리는 것에 덧붙여 시간이 경과해도 가치가 없게 된 항목들을 갖고 있는 경우가 흔하게 됩니다.
- 위와 같은 이런 경우 백그라운드 스레드를 돌리거나, 새 항목을 캐시에 추가할 때 확인하여 null 처리해주는 것이 좋습니다.


3. 콜백( Callback ) 과 리스너 ( Listener ).


- 클라이언트가 콜백을 등록은 하고 말소를 하지 않는다면, 콜백은 계속 누적됩니다.
- 이 역시 쉬운 해결책은 약한 참조 ( Week Reference )인 WeakHashMap 을 사용하는 것입니다.



일반적으로 Memory Leak 은 잘 드러나지 않으므로 오랫동안 시스템에 남아있기 쉽습니다.  코드를 철저하게 검사하거나, 힙 프로파일러( Heap Profiler ) 와 같은 디버깅 tool 의 도움을 받아야만 원인을 찾을 수 있죠. 따라서 미리 예방하는 것이 최선책입니다.

 
로그인 없이 추천 가능합니다. 손가락 꾸욱~

반응형

댓글