세대 단위 컬렉션 이론

  • 대다수 객체는 일찍 사라짐(약한 세대 가설)
  • GC과정에서 살아남은 횟수가 늘어날 수록(앞으로도) 생존 가능성이 높아짐(강한 세대 가설)
  • 다른 세대에 속한 객체간 참조는 같은 세대에 속한 객체간 참조보다 훨씬 작음(세대 간 참조 가설)
  • 핫스팟 VM에서 에덴과 생존자 공간비율을 보통 8:1
    • IBM 연구에 따름(보통 첫 GC에 대락 98% 객체가 소멸)
    • 10%는 메모리 파편화 방지를 위해 활용(Overhead)

Young gereration

  • Eden
    • 객체 생성 직후 저장되는 영역
    • Minor GC 발생 시 Survivor 영역으로 이동
    • Copy & Scavenge 알고리즘
  • Survivor 0, 1
    • Minor GC 발생 시 Eden, S0 에서 살아남은 객체는 S1으로 이동
    • S1에서 살아남은 객체는 Old 영역으로 이동
    • age bit 사용(참조계수)

Old generation

  • Old
    • Young generation 영역에서 소멸하지 않고 남은 객체들이 사용하는 영역
    • Full GC 발생 시 개체 회수
      • 시간이 오래 걸린다
    • Mark & Compact 알고리즘

Permanent

  • Metaspace(Java 8)
    • 로드되는 클래스, 메소드 등에 관한 메타 정보 저장(자동확장 가능)
    • Java Heap이 아닌 Native 메모리 영역 사용
    • 리플렉션 클래스 로드 시 사용(Spring)

대표적인 GC 알고리즘 - Mark and Sweep

  • 1960년대 제안된 가장 기본적 GC 알고리즘으로 후속 알고리즘의 토대
  • 1단계 표시(Mark, 회수 대상 판단), 2단계 회수(Sweep)방식
  • 단점
    • 효율이 일정하지 않음. 특히 힙이 많이 채워져 있을 경우 작업 효율이 매우 떨어진다.
    • 메모리 파편화에 따른 비효율 문제

대표적인 GC 알고리즘 - Mark and Copy

  • 1969년 mark and sweep 을 보완하기 위해 로버트 페니첼이 제안
  • 가용 메모리 공간을 둘로 나눈 후 한쪽만 사용(S0, S1)
    • 한 공간에서 mark and sweep 실시 후 파편화된 조각(살아남은 소수의 인스턴스들)을 다른 공간으로 복사
    • 사용했던 공간을 모두 비우는 식으로 Sweep
  • 단점
    • 가용 메모리 공간이 절반으로 줄어듬
    • 이후 개선이 8(가용공간):1:1 로해서 2를 1:1로 반나눔
      • 1989년 엔드류 아펠의 제안으로 개선

대표적인 GC 알고리즘 - Mark and Compact

  • 생존한 객체 많을 수록 복사해야할 인스턴스가 늘어나는 mark and sweep 단점 극복을 위해 1974년 에드워드 루더스가 제안
  • 1단계 mark후 2단계에서 생존 객체를 한쪽 구석으로 모으고(이동) 나머지만 Sweep
  • 단점
    • 살아남는 객체 많을 수록 부담 크게 증가
    • 인스턴스 이동 과정에서 응용 프로그램의 연산이 일시정지(stop the world)

도달 가능성 분석

  • 도달 가능성 분석 Reachability Analysis 알고리즘에 기초해 회수 대상 인스턴스를 판단
  • GC 루트 객체들을 기점으로 참조하는 다른 객체들을 탐색하는 방식

GC 루트 객체가 될 수 있는 것들

  • JVM stack frame 지역변수 테이블에서 참조하는 객체(현재 실행 중인 메서드)
  • Synchronized 키워드로 잠겨 있는 객체
  • JNI가 참조하는 객체
  • 메서드 영역에서 클래스 정적 필드로 참조하는 객체
  • 메서드 영역에서 상수로 참조되는 객체
  • JVM 내부에서 사용되는 참조

클래식 GC 종류 일부

  • Serial
    • 단일 스레드로 작동. 회수가 끝날 때까지 모두 멈춤
    • 간단하고 효율적이며 알고리즘 수준에서 리소스 사용량 적음
  • ParNew
    • 시리얼 컬렉터를 병렬처리
  • Parallel scavenge
    • 사용자 코드 처리 실행 효율을 극대화를 목표로 설계

클래식 GC 종류

  • CMS(Concurrent Mark Sweep) GC
    • Java 9부터 사용하지 않다가 Java 14에서 G1GC를 지원하고자 완전히 제거
  • G1(Garbage First) GC
    • 4GB 이상 대용량 Heap 메모리를 사용하는 멀티스레드 기반 응용 프로그램에 특화된 GC
    • Heap을 영역(1~32MB)단위로 분할한 후 멀티스레드로 스캔

G1 GC

  • 서버용 응용 프로그램에 집중한 GC
    • JDK 9 부터 기본 GC
  • JVM 힙을 세대단위가 아닌 독립 영역으로 구분해 관리하는 것이 특징
    • Heap을 영역(1~32MB)단위로 분할한 후 멀티스레드로 스캔
  • 힙의 모든 영역을 회수 집합(CSet, Collection Set)에 포함시켜 영역단위 처리
    • 가장 쓰레기가 많은 영역을 파악
    • 회수 시 가장 득이 되는 영역 파악

객체 메모리 레이아웃과 해시코드

  • Hash code는 Object.hashCode() 함수가 호출되는 시점에 계산
  • 나이는 GC에서 살아남은 횟수
  • Lock flag를 객체를 중심으로 멀티스레드 환경에서 경쟁조건이 발생하는 문제를 해결하기 위한 것

C계열은 klass Java계열은 clazz

MD-5 같은 해시함수를 단방향 암호화 수단으로 안쓰는건 이미 역추출하는 알고리즘같은게 존재해서 위험하기때문

핫스팟 VM 객체 Lock flag

Lock flag상태Mark word 저장 정보
00Lightweight lockingLock 레코드(스핀락 동기화)
01Unlock객체의 Hash code 및 나이
01Biased locking스레드, ID, 타임스탬프, 객체 나이
10Heavyweight locking뮤텍스로 동기화
11GC markGC가 객체 이동 중

Object 클래스

  • Java의 모든 클래스의 부모 클래스
  • equals()
    • 매개변수로 전달된 참조자와 this가 가리키는 대상이 같은 값인지 값만 비교(shallow copy 문제)
  • toString()
    • 클래스명@해시코드

’같다’라는 의미

  • 해시코드가 같은 인스턴스는 존재하지 않음
  • 가리키는(참조하는) 대상이 같은 경우
    • 인스턴스가 가진 값과 관련 없다
  • 인스턴스 a, b, c는 모두 같은 클래스의 인스턴스
    • 같은 클래스의 인스턴스라해도 각각은 독립적
    • (모든) 필드의 값이 같으면 논리적으로 같음. 내용이 같음
  • 클래스가 같고 인스턴스값(메모리에 저장된 내용)까지 같은 경우

equals()의 기본 동작은 참조값만 비교한다! 내용비교를 하고싶으면 오버라이딩을 하는 것.

동등성(Equality)와 동일성(Identity)

  • 두 인스턴스를 비교해 같은 클래스 인스턴스이며 내용도 일치하는지 비교하는 것이 동등성
    • Deep copy 처럼 두 인스턴스 내용을 비교
  • 동일성은 같은 한 인스턴스에 대한 참조자인지 값을 비교
    • Shallow copy 처럼 참조자 값만 비교
    • 한 인스턴스를 가리키는 것인지 확인