반응형
아이템 7. 다 쓴 객체 참조를 해제해라
다 쓴 객체 참조를 해제하라
JDK 8버전 코드
public class Stack{
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack(){
elements = new Object [DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e){
ensureCapacity();
elements[size++] = e;
}
public Object pop(){
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
private void ensureCapacity(){
if(elements.length == size)
elements = Array.copyOf(elements, 2 * size + 1);
}
}
JDK 8버전에서는 현재 index를 변경해서 stack의 top을 관리하지만 pop()을 할때 TOP의 값을 줄이기만 합니다. 이 부분에서 문제가 발생합니다.
참조 무효화
public pop(){
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete references.
return result;
}
기존 stack 방식
객체를 스택에 추가
객체를 스택에 추가
기존 stack 방식
스택은 객체를 삭제하는게 아닌 참조는 계속한 상태로 top idx만 변경
이렇게 사용하지 않는 객체를 계속해서 보관하고 있다면 메모리 누수
가 발생합니다.
null 처리
null처리를 해주게 되면 GC가 해당 객체를 정리함
2023.11.09 - [JAVA] - [JAVA] GC란?
메모리 낭비를 줄이는 방법
스코프 밖으로 밀어내라
public void test() {
if(true){
Integer a = 10; // if문의 종료되면 변수가 해제
}
}
JDK 11 실제 Stack구현부
public synchronized void removeElementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
modCount++;
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
실제 Stack의 구현부 입니다. JDK 11버전 에서는 null
처리를 통해 객체 참조 해제를 해줘서 Stack을 사용해도 메모리 누수의 문제로부터 안전합니다.
캐시 메모리 누수
- 객체 참조를 캐시에 넣고 제거 안하면 지속적인 참조 때문에 메모리 누수가 발생
Map<Object, String> map = new HashMap<>();
HashMap은 강한결합 객체의 한종류로 직접적으로 key를 해제하지 않으면 메모리 누수가 발생합니다.
해결 방안:
- WeakHashMap을 사용하여 외부에서 해당 key 객체가 살아있는 동안은 key: value가 살아있다.(약한 참조) key가 상수 풀에 저장돼있으면 적용 안됩니다.(Ex: primitive type, int, char...)
Map<Object, String> map = new WeakHashMap<>();
Java – Collection – Map – WeakHashMap (약한 참조 해시맵)
예시코드
HashMap
public static void hashMap() {
HashMap<Integer, String> map = new HashMap<>();
Integer num1 = new Integer(10);
String str1 = new String("str1");
Integer num2 = new Integer(20);
String str2 = new String("str2");
map.put(num1, str1);
map.put(num2, str2);
System.out.println(map.toString());
num1 = null;
System.gc();
System.out.println(map.toString());
}
WeakHashMap
public static void weakHashMap(){
WeakHashMap<Integer, String> map = new WeakHashMap<>();
Integer num1 = new Integer(10);
String str1 = new String("str1");
Integer num2 = new Integer(20);
String str2 = new String("str2");
map.put(num1, str1);
map.put(num2, str2);
System.out.println(map.toString());
num1 = null;
System.gc();
System.out.println(map.toString());
}
약한 참조를 하는 WeakHashMap에서는 key를 담당하는 객체가 null
로 참조해제를 하면 WeakHashMap은 해당 key를 제거하게 됩니다.
결과
WeakHashMap은 key를 참조해제 했을 때 key가 사라진것을 볼 수 있으며 HashMap은 강한결합 때문에 key로 가지고 있어 메모리 누수가 발생할 수 있습니다
참조
이펙티브 자바
반응형
'JAVA' 카테고리의 다른 글
[Java] Relection 메소드 필드명 가져오기 arg0, arg1 (0) | 2024.04.28 |
---|---|
[Java] TreeSet의 구조와 주의사항 (0) | 2024.02.29 |
[Java] 동적 프록시에 대해 (0) | 2023.11.28 |
[JAVA] GC란? (0) | 2023.11.09 |
정적 팩토리 메소드의 장단점 (0) | 2023.07.07 |