본문 바로가기

Language/JAVA

[이펙티브 자바][아이템 7] 다 쓴 객체 참조를 해제해라 - 컴도리돌이

728x90

자바 프로그래밍을 하다 보면 한 번쯤은 "메모리 누수"라는 문제를 들어본 적이 있을 거예요. 그렇다면 메모리 누수가 실제로 어떻게 발생할까요? 자바는 가비지 컬렉터(Garbage Collector, GC)를 통해 사용하지 않는 객체를 자동으로 수거하는데, 그렇다면 왜 우리는 여전히 메모리 누수를 걱정해야 할까요?? 🤔

 

가비지 컬렉터가 잘못된 객체를 수거하지 못하게 만드는 주된 이유 중 하나는 바로 다 쓴 객체에 대한 참조를 해제하지 않기 때문이에요. 이 문제는 특히 메모리를 장시간 사용하거나, 많은 객체를 다루는 애플리케이션에서 더 심각하게 드러난다고 합니다. 가령, 우리가 다 쓴 객체를 필요 이상으로 참조하고 있는 경우, 해당 객체는 가비지 컬렉터의 대상이 되지 않으며, 그 결과 메모리가 불필요하게 사용됩니다. 

import org.springframework.stereotype.Component;

@Component
public class UserContext {

    private static final ThreadLocal<String> userThreadLocal = new ThreadLocal<>();

    public void setUser(String user) {
        userThreadLocal.set(user);
    }

    public String getUser() {
        return userThreadLocal.get();
    }

    public void clear() {
        userThreadLocal.remove(); // 다 쓴 객체 참조 해제
    }
}

 

위 코드에서는 clear() 메서드를 호출하지 않으면, ThreadLocal에 저장된 값이 계속 메모리에 남아 있을 수 있어요. 이는 특히 스레드 풀을 사용하는 환경에서는 심각한 문제가 되겠죠. 스레드가 재사용되면서 이전에 저장된 값이 남아 있게 되고, 이로 인해 메모리 누수가 생길 수 있습니다. 🫠🫠

 

그러면 메모리 누수가 발생하면 어떤 일이 벌어질까요?

 

메모리 누수는 시간이 지남에 따라 애플리케이션의 메모리 사용량을 증가시키고, 결국 OutOfMemoryError를 초래할 수 있어요. 이런 문제는 장시간 실행되는 서버 애플리케이션에서 특히 치명적이며, 실제로 많은 개발자들이 메모리 누수 문제를 겪으며 애플리케이션 성능이 저하되는 현상을 경험하게 되는데 더 자세한 것은 다음 링크를 보면서 확인할 수 있어요. 

 

 

How can I create a memory leak in Java?

I just had an interview where I was asked to create a memory leak with Java. Needless to say, I felt pretty dumb, having no idea how to start creating one. What would an example be?

stackoverflow.com

 

그렇다면 이러한 문제를 어떻게 해결할 수 있을까요? 🤔

가장 간단한 방법은 다 쓴 객체의 참조를 null로 명시적으로 해제하는 것이에요. 

 

이렇게 객체를 null로 설정하여, 참조를 해제를 하게 되면 해당 객체가 가비지 컬렉션의 대상이 되어 메모리가 올바르게 해제될 수 있어요. 그러나 여기서 중요한 점은 모든 객체 참조를 null로 설정하는 것은 좋은 습관이 아니며, 필요한 경우에만 사용해야 한다는 것이에요!

예를 들어, 사용된 객체가 더 이상 필요하지 않다는 것이 명확한 경우에만 참조를 null로 설정하는 것이 좋습니다. 

 

그러면 객체를 언제 null로 참조를 해제해야 할까요? 

 

먼저 직접 관리하는 메모리 구조에서, 예를 들어 배열과 같은 자료 구조를 사용할 때 필요해요. 두 번째는 오랜 시간 동안 유지되면서 많은 객체를 참조하는 경우, 참조 해제를 통해 메모리 사용을 줄일 수 있어요.

 

이 두 가지에 해당하지 않은 경우는 가비지 컬렉션이 대부분의 메모리 관리를 알아서 처리해 주기 때문에 굳이 null로 참조를 설정하지 않아도 괜찮습니다. 점점 자바 버전 업이 되면서 메모리 관리를 더 잘 수행하도록 개선된 GC 알고리즘을 사용하고 있어요. 자바 21 버전에서는 새롭게 도입한 ZGC를 통해서 메모리 자원을 효율적으로 관리하고 있어요. 처리량이 이전 버전보다 10% 개선되었다고 하는데 자세한 부분은 아래 링크롤 통해서 읽어보세요 😊

 

 

Introducing Generational ZGC – Inside.java

ZGC was updated as part of JDK 21 to be a generational garbage collector. What does this mean for your Java applications? Let's take a look.

inside.java

 

JVM과 Garbage Collection - G1GC vs ZGC

Java Memory 자바 개발자라면 꼭 알고 넘어가야 하는 기본 아닌 기본 소양 📝 JVM 처음부터 다 설명하는 것은 제가 이야기하고자 하는 포인트가 아니라서, 간략하게 중요한 것만 짚고 넘어가려고 합

huisam.tistory.com