java-squid / effective-java

effective java 3e study
105 stars 38 forks source link

[아이템 07] 다 쓴 객체 참조를 해제하라 #7

Closed wooody92 closed 4 years ago

guswns1659 commented 4 years ago

p.38 (4번째 문단) 캐시 역시 메모리 누수를 일으키는 주범이다.

여기서 의미하는 캐시는 자주 사용되는 인스턴스를 특정 상수에 담고 있는 기술을 의미하겠죠? 아이템6의 코드6-2의 예시처럼 말이죠?

guswns1659 commented 4 years ago

p.39 (마지막 문단) 메모리 누수의 세 번째 주범은 바로 리스너(listner) 혹은 콜백(callback)이라 부르는 것이다.

개발 공부하면서 종종 만났던 키워드가 리스너와 콜백인데 자바를 사용하면서 어떻게 적용되는 지 모르겠네요! 두 키워드에 대해 간단한 개념 설명해주시면 좋을 것 같습니다.

wooody92 commented 4 years ago

p.38 객체 참조를 null 처리하는 일은 예외적인 경우여야 한다. 다 쓴 참조를 해제하는 가장 좋은 방법은 그 참조를 담은 변수를 유효 범위(scope) 밖으로 밀어내는 것이다.

참조를 담은 변수를 유효 범위(scope) 밖으로 밀어낸다는 것이 어떤 방식을 말하는 걸까요?

wooody92 commented 4 years ago

강한참조와 약한참조 찾아보다가 d2에 좋은 글이 있어 공유합니다. https://d2.naver.com/helloworld/329631

A) weak referenece : 다음 G.C 사이클에 정리 soft, strong reference : 메모리 부족할 때 G.C가 정리

david215 commented 4 years ago

위 d2 글보다 깊이는 많이 부족하지만 이해는 더 쉬운 링크: Guide to WeakHashMap in Java

wooody92 commented 4 years ago

@guswns1659

p.38 (4번째 문단) 캐시 역시 메모리 누수를 일으키는 주범이다.

여기서 의미하는 캐시는 자주 사용되는 인스턴스를 특정 상수에 담고 있는 기술을 의미하겠죠? 아이템6의 코드6-2의 예시처럼 말이죠?

네. 동일하게 이해했습니다. 다만 여기서 캐시를 사용할 때 WeakHashMap방식이나 LinkedHashMap으로 덜 중요한 엔트리를 null 처리 하는 것으로 보이는데, static 영역에 있는 static 상수를 null 처리한다는 것이 잘 이해가 안가네요. 힙 영역과 다르게 스태틱 영역은 애플리케이션 실행시 고정되어 있는 값들로 이해했거든요. static으로 선언한 변수들도 final로 고정 하지 않은 경우에 null 처리하면 G.C에 의해 메모리에서 지워질까요?

A) Item 6-2 예제는 다양한 캐싱 전략중 하나이고, 여기서 말하는 캐시는 다른 방식으로 구현한 캐싱 전략이다. static 영역은 가비지 컬렉터의 영역이 아니다.

A) WeakHashMap : key값에 null을 주면 다음 사이클에 G.C가 처리?

han0102 commented 4 years ago

@wooody92

참조를 담은 변수를 유효 범위(scope) 밖으로 밀어낸다는 것이 어떤 방식을 말하는 걸까요?

확실하지 않지만, 제 생각에는 객체 참조 형태를 unreachable하게 만들어준다는 의미 같습니다.

좀 더 예시를 들자면, ArrayList에 어떤 객체를 참조하는 변수들이 0,1,2 총 3개 존재한다고 할 때, remove() 메서드를 통해 특정 인덱스를 리스트 내에서 제거하기만 하면(참조를 담은 변수를 유효 범위 밖으로 밀어내면), 해당 인덱스가 가르키고 있던 특정 객체의 참조 상태가 unreachable로 바뀌므로 자동적으로 GC의 대상이 되는 과정이지 않을까 생각합니다..


지역변수를 선언할 때, 해당 scope에서만 선언하도록 만들어라. for문 내부에, 사용하는 변수는 그 외부에 선언을 해놓으면 GC가 자동으로 정리해주지 못한다.

han0102 commented 4 years ago

@wooody92

static으로 선언한 변수들도 final로 고정 하지 않은 경우에 null 처리하면 G.C에 의해 메모리에서 지워질까요?

static으로 선언한 정적 변수들은, JVM Runtime Area중 Method Area로 올라가는 것으로 알고 있습니다. GC의 대상은 Heap 영역일 꺼에요. 즉 Method Area는 GC의 대상이 아니지 않을까요?

han0102 commented 4 years ago

@guswns1659

p.39 (마지막 문단) 메모리 누수의 세 번째 주범은 바로 리스너(listener) 혹은 콜백(callback)이라 부르는 것이다.

콜백(Callback) : 이벤트가 발생하면 특정 메소드를 호출해 알려준다. (1개) 리스너(Listener) : 이벤트가 발생하면 연결된 리스너(핸들러)들에게 이벤트를 전달한다 (n개)

콜백과, 리스너는 위와 같이 정의하고 있는 데요.. 명칭에서 느낄 수 있듯이 이벤트를 기다린다는 비슷한 점이 있는 듯 합니다. 그런데 이 두가지가 어떻게 메모리 누수를 유발할 수 있을까요?

간단하게 생각해보자면, 아마도 콜백, 리스너가 인스턴스로 만들어져 어떠한 이벤트를 기다린다고 생각해 볼때, 그 기다리고 있는 이벤트가 오지 않는다면, 아마도 해당 클래스들은 의미도 없이 heap에 자리를 차지하고 있는 셈이되고, 결국엔 이게 memory leak을 의미하지 않을까 생각합니다..

확실하진 않습니다. 한번 얘기 나눠보면 좋을듯 합니다~

kses1010 commented 4 years ago

p.38 (마지막 문단) 'WeakHashMap'을 사용해서 캐시를 만들자.

여기서 WeakHashMap을 사용하여 만든 캐시의 예를 들 수 있을 까요? 그리고 그다음 내용

캐시를 만들 때 보통은 캐시 엔트리의 유효 기간을 정확히 정의하기 어렵기 때문에 시간이 지날수록 엔트리의 가치를 떨어뜨리는 방식을 흔히 사용한다. 이런 방식에서는 쓰지 않는 엔트리를 이따금 청소해줘야 한다. (ScheduledThreadPoolExecutor 같은) 백그라운드 스레드를 활용하거나 캐시에 새 엔트리를 추가할 때 부수 작업으로 수행하는 방법이 있다.

백그라운드 스레드를 활용하는 방법이 정확하게 어떤건가요? 캐시부터는 제대로 사용하지 않아서 어떤 역할을 하는지 많이 어렵군요.

102092 commented 4 years ago

@kses1010

여기서 WeakHashMap을 사용하여 만든 캐시의 예를 들 수 있을 까요?

  1. 캐시의 예는 아래 코드를 참고하시는게 좋을듯 합니다.

백그라운드 스레드를 활용하는 방법이 정확하게 어떤건가요?

  • 저는 배치 작업같은 느낌으로 받아드렸습니다. 스레드 A,B가 있다고 가정했을 때, A에서는 map에 캐시를 넣고, 빼는 등의 작업만 담당하여 계속하되, B에서는 일정 시간마다 map에 있는 key들이 유효한 값인지 확인하는 주기적인 작업을 진행한다라고 이해했습니다. 그래서 ScheduledThreadPoolExecutor를 책에서 언급한듯 싶습니다.
kses1010 commented 4 years ago

유효범위에 대한 예시를 위한 사진 image