콘텐츠로 이동

자바 메모리 관리, 람다, GC 및 OOP 개념 심층 분석

1. 객체 생성과 메모리 관리 구조

1.1 힙 인스턴스 참조 저장 위치

new 연산자로 생성된 객체는 **힙 영역**에 저장되며, 이 인스턴스를 가리키는 참조 값은 다음 두 위치에 저장됩니다:

public class MemoryExample {
    private Object instanceField = new Object();  // 힙 내 객체의 참조 저장

    public void method() {
        Object localVar = new Object();  // 스택 프레임에 참조 저장
        System.out.println(localVar);
    }
}
  • 스택 저장: 메서드 내 지역 변수(localVar)는 스택 프레임에 4/8바이트 참조 값 저장19
  • 힙 저장: 인스턴스 변수(instanceField)는 해당 객체의 힙 메모리 구조 내부에 저장10

메모리 구조 (출처: JVM 메모리 구조 도식화)1

1.2 잘못된 참조 관리 예시

public class ReferenceLeak {
    private static List<byte[]> leakList = new ArrayList<>();

    public void generateData() {
        while(true) {
            byte[] data = new byte[10_000_000];  // 매회 10MB 할당
            leakList.add(data);  // 정적 컬렉션에 참조 유지 → GC 불가
        }
    }
}

이 코드는 **메모리 누수**를 유발하며, OutOfMemoryError 발생49


2. Private 메서드 vs Lambda 표현식

2.1 핵심 차이점 비교

특성 Private 메서드 Lambda 표현식
접근 제어 클래스 내부에서만 호출 가능 함수형 인터페이스 구현
상태 접근 인스턴스 변수 직접 접근 final/effective final 변수만 캡처14
바이트코드 생성 일반 메서드로 컴파일 invokedynamic 사용311
직렬화 기본 지원 SAM 인터페이스 구현 필요

2.2 코드 예시

public class LambdaVsPrivate {
    private int counter = 0;

    private void increment() {
        counter++;  // 인스턴스 변수 직접 수정 가능
    }

    public Runnable getLambda() {
        int localCounter = 0;
        return () -> {
            // counter++;  // 컴파일 에러 (람다 캡처링 규칙 위반)
            localCounter++;  // 컴파일 에러 (effective final 위반)
            System.out.println("Lambda executed");
        };
    }
}

3. 가비지 컬렉션 메커니즘

3.1 세대별 수집 전략

graph LR
A[Young Generation] --> B[Eden]
A --> C[Survivor S0]
A --> D[Survivor S1]
E[Old Generation]
F[Permanent/Metaspace]

B -- Minor GC --> C
C -- 객체 Age 증가 --> D
D -- 임계치 초과 --> E
E -- Major GC --> F
  • Minor GC: Young 영역 (Eden → Survivor)9
  • Major GC: Old 영역 (Mark-Sweep-Compact)4
  • G1 GC: 영역 분할과 예측 기반 수집 (Java 9+ 기본)

3.2 GC 최적화 예시

// 비효율적 코드
List<Data> processData(List<RawData> inputs) {
    return inputs.stream()
        .map(raw -> new DataParser().parse(raw))  // 매번 parser 생성
        .collect(Collectors.toList());
}

// 최적화 코드
public class DataProcessor {
    private static final DataParser PARSER = new DataParser();  // 재사용

    List<Data> optimizedProcess(List<RawData> inputs) {
        return inputs.stream()
            .map(PARSER::parse)  // 정적 파서 재사용
            .collect(Collectors.toList());
    }
}

4. OOP 개념과 Spring Boot 구현

4.1 인터페이스/클래스 활용

// 제네릭 인터페이스
public interface CrudRepository<T, ID> {
    T save(T entity);
    Optional<T> findById(ID id);
}

// 구현 클래스
@Service
public class UserRepositoryImpl implements CrudRepository<User, Long> {
    @Override
    public User save(User user) {
        // JPA/Hibernate 구현
        return entityManager.merge(user);
    }
}

// Spring Data JPA 활용
public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.email = ?1")
    Optional<User> findByEmail(String email);
}

4.2 의존성 주입 예시

@RestController
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;  // 생성자 주입

    @PostMapping("/users")
    public ResponseEntity<User> createUser(@RequestBody UserDto dto) {
        return ResponseEntity.ok(userService.createUser(dto));
    }
}

5. 성능 최적화 기법

5.1 인스턴스 생성 비용 관리

// 비효율적
@GetMapping("/report")
public Report generateReport() {
    return new ReportGenerator().generate();  // 매번 생성자 호출
}

// 최적화
@Service
@Scope("prototype")  // 필요시 인스턴스 생성
public class ReportGenerator {
    @PostConstruct
    public void init() {
        // 무거운 초기화 작업
    }
}

@RestController
@RequiredArgsConstructor
public class ReportController {
    private final ObjectFactory<ReportGenerator> generatorFactory;

    @GetMapping("/report")
    public Report generate() {
        return generatorFactory.getObject().generate();
    }
}

5.2 캐싱 전략

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("users");
    }
}

@Service
public class UserService {
    @Cacheable("users")
    public User getUserById(Long id) {
        // DB 조회 로직
        return repository.findById(id).orElseThrow();
    }
}

6. 결론: 핵심 개념 요약

구분 주요 내용 성능 영향 요소
메모리 관리 스택-힙 분리 저장, 참조 카운팅 기반 GC 객체 생명주기 관리
람다 특성 캡처 변수의 불변성 유지, 함수형 인터페이스 구현 스택 트레이스 복잡도 증가
GC 전략 세대별 분리 수집, Stop-The-World 시간 최소화 Full GC 발생 빈도
OOP 설계 인터페이스 분리 원칙(ISP), 의존성 역전(DIP) 클래스 결합도
Spring 최적화 빈 스코프 관리, 캐싱, 연결 풀 설정 컨텍스트 로드 시간

성능 개선을 위한 체크리스트:

  1. 불필요한 객체 생성 줄이기 (예: 정적 팩토리 메서드)
  2. @Cacheable을 활용한 반복 작업 캐싱
  3. 스레드 풀 적절한 설정 (TaskExecutor 튜닝)
  4. JPA N+1 문제 방지 (페치 조인 사용)
  5. GC 로그 분석을 통한 힙 크기 조정

  1. https://inblog.ai/muaga/jvm-실행-시-저장-진행-상황static-heap-stack-20575 

  2. https://8iggy.tistory.com/230 

  3. https://velog.io/@redjen/lambda-vs-inner-anonymous-class 

  4. https://kim-oriental.tistory.com/48 

  5. https://velog.io/@gale4739/Spring-Boot-Interface-골격-구현-클래스-클래스-구조-변경Feat.-Composition 

  6. https://www.lgcns.com/blog/cns-tech/aws-ambassador/49072/ 

  7. https://meal-coding.tistory.com/16 

  8. https://velog.io/@newd/실전-스프링-부트와-JPA-활용2-API-개발과-성능-최적화-정리4 

  9. https://sharplee7.tistory.com/54 

  10. https://velog.io/@dmchoi224/참조형-변수-짚고-가기 

  11. https://inpa.tistory.com/entry/☕-Lambda-Expression 

  12. https://devloo.tistory.com/entry/Spring-Boot-의-성능을-향상시키는-10가지-방법 

  13. https://sjh836.tistory.com/173 

  14. https://bbidag.tistory.com/27 

  15. https://tech.kakaopay.com/post/spring-batch-performance/ 

  16. https://cbjh-4.tistory.com/79 

  17. https://inpa.tistory.com/entry/JAVA-☕-그림으로-보는-자바-코드의-메모리-영역스택-힙 

  18. https://lealea.tistory.com/273 

  19. https://lucas-owner.tistory.com/38 

  20. https://velog.io/@devnoong/JAVA-Stack-과-Heap에-대해서 

  21. https://inpa.tistory.com/entry/☕-Lambda-Expression 

  22. https://velog.io/@haminggu/Java-가비지-컬렉션-동작-원리 

  23. https://gnidinger.tistory.com/entry/Java인터페이스의-활용-예제 

  24. https://devloo.tistory.com/entry/Spring-Boot-의-성능을-향상시키는-10가지-방법 

  25. https://blog.naver.com/senshig/221759831074 

  26. https://jerrys-ai-lab.tistory.com/34 

  27. https://breakcoding.tistory.com/4 

  28. https://inpa.tistory.com/entry/JAVA-☕-가비지-컬렉션GC-동작-원리-알고리즘-💯-총정리 

  29. https://velog.io/@songsunkook/함수형-인터페이스와-표준-API 

  30. https://codegym.cc/ko/groups/posts/ko.250.javaui-lamda-pyohyeonsig-e-daehan-seolmyeong-ibnida-yejewa-jag-eob-i-issseubnida-1-bu 

  31. https://www.inflearn.com/blogs/6665 

  32. https://nohriter.tistory.com/166 

  33. https://butter-shower.tistory.com/85 

  34. https://velog.io/@koo8624/Spring-JPA-성능-최적화 

  35. https://devloo.tistory.com/entry/스프링-부트-지금-당장-적용해야-할-25가지-Spring-Boot-모범-사례 

  36. https://yoonseon.tistory.com/35 

  37. https://nightsky-stars.tistory.com/entry/springboot-실전-스프링부트와-JPA-활용2-API-개발과-성능-최적화-2-API-개발-고급-준비-지연-로딩과-조회-성능-최적화 

  38. https://youseong.tistory.com/29 

  39. https://aspring.tistory.com/entry/스프링부트-실전-스프링-부트와-JPA-활용2-컬렉션-조회-최적화-31-페이징과-한계-돌파