개발 기록

[이펙티브 자바] 아이템 7,8 본문

JAVA

[이펙티브 자바] 아이템 7,8

수염차 2024. 10. 3. 21:20

(7) 다 쓴 객체 참조를 해제하라

 

가비지 컬렉터가 있더라도 메모리 관리에 신경써야 함! *메모리 누수*

 

가비지 컬렉션 언어에서는 메모리 누수를 찾기가 어려움.

객체 참조를 하나 살려두면 그 객체 + 그 객체가 참조하는 모든 객체 +.. 를 회수 하지 못 함.

 

해법!

 

1. 해당 참조를 다 썼을 때 null 처리 (참조 해제)

**예외적인 경우에 사용 : 자기 메모리를 직접 관리하는 클래스일때

ex. 스택 클래스에서 pop 메서드를 제대로 구현 (꺼낸 객체는 참조가 더 이상 필요 없음)

public Object pop() {
		if (size = 0)
			throw new EmptyStackException();
		Object result = elements[--size];
		elements[size] = null; // 다 쓴 참조 해제
		return result;
}

 

2. WeakHashMap

: 더이상 사용하지 않는 객체를 GC할 때 자동으로 삭제해주는 Map

** 캐시 외부에서 키를 참조하는 동안만 엔트리가 살아 있는 캐시가 필요한 상황.

public static void main(String[] args) {
		WeakHashMap<Integer, String> weakHashMap = new WeakHashMap<Integer, String>();

		Integer key = new Integer(1);
		weakHashMap.put(key, "1");
		key = null;

		// If GC is generated, the output changes to {}.
		while (true) {
			System.out.println(weakHashMap);
			System.gc();
			if (weakHashMap.size() == 0) {
				break;
			}
		}

		System.out.println("End");
	}

해당 코를 실행해보면 key를 강하게 참조하는 곳이 없기 때문에 GC할 때 캐시가 지워진다.

 

참고로, String 클래스를 Key로 하는 WeakHashMap을 사용하면 의미가 없다. 왜냐하면 규칙 5에서 설명했듯이 String은 내부적으로 한 번 생성된 String에 대해 Constant Pool에 항상 참조가 존재하기 때문이다.

[출처] https://camel-context.tistory.com/42

 

리스너나 콜백도 약한 참조로 저장하면 가비지 컬렉터가 즉시 수거해감

- 콜백함수 : 다른 코드의 인수로서 넘겨주는 실행 가능한 코드

 

메모리 누수는 겉으로 잘 드러나지 않아 시스템에 수년간 잠복하는 사례도 있다. 

이런 누수는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원해야만 발견되기도 한다. 

그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요하다.

 


 

(8) finalizer와 cleaner 사용을 피하라

 

자바가 제공하는 두가지 객체 소멸자

 

1. finalizer

- 예측 할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요.

 - 오동작, 낮은 성능, 이식성 문제의 원인

- finalizer 스레드는 다른 애플리케이션 스레드보다 우선순위가 낮아서 실행될 기회를 제대로 얻지 못할 수 있다.

- finalizer 동작 중 발생한 예외는 무시되며, 처리할 작업이 남았더라도 그 순간 종료된다.

- finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수 있다.

 

2. cleaner 

- 자바 9에서 finalizer 대안으로 소개

- 덜 위험하지만 여전히 예측할 수 없고, 느리고, 일반적으로 불필요

- 여전히 백그라운드에서 수행되며 가비지 컬렉터의 통제하에 있으니 즉각 수행되리라는 보장이 없다.

 

** 위 두가지 대신 쓸 수 있는 AutoCloseable 클래스

- 사용 방법 : AutoCloseable을 구현해주고, 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출

(일반적으로 예외가 발생해도 제대로 종료되도록 try-with-resources 를 사용)

public class AutoCloseableExample {
    public static void main(String[] args) {
        try (CustomResource customResource = new CustomResource()){
    		//close() 호출
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}


public class CustomResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("CustomResource Closed!");
    }
}

'JAVA' 카테고리의 다른 글

[이펙티브자바] 아이템12  (0) 2024.10.23
[이펙티브 자바] 아이템 11  (1) 2024.10.15
[이펙티브 자바] 아이템 6  (2) 2024.10.03
[이펙티브 자바] 아이템 4,5  (3) 2024.09.08
[이펙티브 자바] 아이템3  (0) 2024.09.07
Comments