[JVM] OopMap으로 참조체인 내 속한 객체 찾기

2025. 12. 27. 13:49·CS/JVM

 

루트 노드 열거

GC를 시작하려할 때 가장 기본이되는 것이 GC루트를 기준으로 '도달 가능성 알고리즘'을 실행시키는 것이다.

루트 노드 열거는 도달 가능성 알고리즘을 구현하기 위해서 GC 루트집합으로부터 참조체인을 찾는 작업을 뜻한다. GC루트는 주로 전역참조(정적필드 등)와 실행 콘텍스트(스텍 프레임의 지역변수테이블 등)가 사용된다.

 

루트 노드 열거에서 가장 중요한 것은 참조체인을 조사할 때 객체들의 참조관계가 일관성을 유지해야한다는 것이다. 즉, 루트 노드 열거를 실행할 때의 모든 객체들은 추가되거나 삭제되는 것, 다른 객체와 참조관계를 형성하는 작업을 일절 수행하지 않는, 프래그램이 완전히 정지된 상태에서 실행되더야한다. 그리고 이것이 GC가 실행될 때 모든 사용자 스레드가 일시정지되는 이유다.

 

주류 자바 가상머신들은 '정확한 가비지컬렉션'을 사용한다.


정확한 가비지컬렉션

이 '정확한 가비지컬렉션'이란, '정확한 메모리 관리' 기술을 사용하는 가비지컬렉션을 의미한다.

그리고 '정확한 메모리 관리'란, 가상 머신이 메모리 특정 위치에 있는 데이터의 구체적인 자료형을 알 수 있다는 뜻이다. 특정 메모리에 정수 1234가 저장되어있다면, 이것이 원시형 int인지, 아니면 참조값인지 구분을 할 수 있다는 뜻이다.

 

핫스팟 VM이 등장하기 이전에는 클래식 VM이 사용되었는데, 문제는 클래식VM의 GC과정이 추측으로 이루어져있다는 점이었다.

클래식 VM은 '정확한 메모리 관리'를 지원하지 않는 VM으로, 특정 메모리에 있는 값이 정수값인지 참조값인지 구분할 수 없었다. 그래서 저장된 값이 힙메모리의 메모리 주소 범위에 속한다면 그냥 참조값이라고 추정하고 넘겼다.

 

이러한 '간접적인 방식'의 문제점은 객체를 제대로 지우지 못한다는 뜻이다. 만약에 12345번 메모리에 저장된 값의 참조가 해제되었으나 정수형 12345가 현재 스택 지역변수테이블에 저장되어있다면 12345번 메모리에 저장된 객체는 GC의 대상이 되지 않는다. 

 

또 클래식 VM은 '핸들방식'을 사용하여 객체를 관리했다.

https://dev-dx2d2y-log.tistory.com/150

 

[Java] JVM 밑바닥까지 파헤치기 독서 #3 - 자바는 어떻게 객체를 불러오는가?

https://dev-dx2d2y-log.tistory.com/139 [CS] JVM 밑바닥까지 파헤치기 독서 #2 - 자바는 어떻게 객체를 저장하는가?https://dev-dx2d2y-log.tistory.com/138 [CS] JVM 밑바닥까지 파헤치기 독서 #1 - 자바 런타임 메모리 영

dev-dx2d2y-log.tistory.com

핸들방식이란 객체를 저장하는데 실제 객체와 객체의 타입 정보를 핸들을 거쳐서 확인하도록하는 데이터 저장방식인데, 안정적이긴하지만 느리다.

 

여기에 현대 자바는 필요하거나 중요한 부분만 컴파일해서 사용하지만 이당시 자바는 코드전체를 컴파일한다는 점과 맞물려서 초기 자바는 매우 느린 언어였다. C, C++보다 효율이 느렸다.


이그잭트 VM과 정확한 메모리 관리의 등장

JDK1.2에서 이그잭트 VM이 등장했다. 이그잭트 VM은 '정확한 메모리 관리'가 가능한, 즉 가상 머신이 특정 메모리 위치에 있는 객체의 타입을 알 수 있는 가상머신이다. 따라서 클래식 VM처럼 스레드가 정지한 후 실행 콘텍스트와 전역참조의 위치를 모조리 확인할 필요는 없어졌다.

 

단지 객체 참조가 저장된 위치에 직접 접근하기만하면 끝. '객체 참조가 저장된 위치'가 전역변수나 현재 실행중인 스택의 지역변수 테이블과 같은 GC루트가 되는 것이다.

 

이러한 점은 이그잭트 VM에서 시작하여 현재 핫스팟 VM에까지 내려져오는 메모리 관리방법이 되었다.


OopMap

그래서 객체 참조가 저장된 위치에 직접 접근하기위해 OopMap이라는 자료구조를 사용하여 접근한다.

위에서 "'객체 참조가 저장된 위치'가 전역변수나 현재 실행중인 스택의 지역변수 테이블과 같은 GC루트가 되는 것이다."라고 한 것처럼, OopMap은 현재 실행중인 스택 등, GC루트가 될 수 있는 곳에서 참조가 일어나는 부분을 찾는데까지만 쓰인다. 그 뒤로는 각 참조별 객체에 접근해서 직접 klass 구조체를 읽는다.

 

https://dev-dx2d2y-log.tistory.com/139

 

[CS] JVM 밑바닥까지 파헤치기 독서 #2 - 자바는 어떻게 객체를 저장하는가?

https://dev-dx2d2y-log.tistory.com/138 [CS] JVM 밑바닥까지 파헤치기 독서 #1 - 자바 런타임 메모리 영역C와 C++은 객체 (C에는 객체가 없지만)의 생성, 관리, 삭제까지 모두 관리할 책임을 가지지만, 자바에서

dev-dx2d2y-log.tistory.com

이전에 자바는 객체를 저장할 때 객체 레이아웃을 위와같이 잡는다고 했는데, 여기서 클래스워드에 klass 구조체를 나타내는 klass 포인터가 들어간다.

 

그래서 클래스 로딩부터 살펴보자면, 클래스 로딩이 완료되면 객체에 포함된 각 데이터의 타입을 확인한다.

https://dev-dx2d2y-log.tistory.com/138

 

[CS] JVM 밑바닥까지 파헤치기 독서 #1 - 자바 런타임 메모리 영역

C와 C++은 객체 (C에는 객체가 없지만)의 생성, 관리, 삭제까지 모두 관리할 책임을 가지지만, 자바에서는 JVM이 대체적으로 이 역할을 수행한다. JVM에 대해서 배우면서 가장 먼저 자바 메모리 영역

dev-dx2d2y-log.tistory.com

 

JVM 밑바닥까지 파헤치기 독서 #1

클래스가 로딩되고나면 klass 구조체가 하나 만들어지게되는데, 이를 통해서 각 클래스에 포함된 데이터들의 타입을 확인한다. 클래스에 있는 변수가 참조형 변수인지, 아니면 원시형변수인지 분간을 하게된다.

 

그리고 이 klass 구조체를 읽어가며 JIT컴파일러(자주 실행되는 코드만 부분적으로 컴파일하는 컴파일러 | 뒤에서 다룰 예정)가 스택의 어느 슬롯과 어느 레지스터가 참조인지 기록한다. (JIT컴파일러는 레지스터를 주로 사용하는데, 이는 나중에 다룬다.)

 

왜 JIT컴파일러가 참조하는 '스택'과 '레지스터'만 다루냐면, 위에서 말했듯이 OopMap을 사용하는 이유는 GC루트에서 참조가 일어나는 부분만 찾기 위해서이다. GC루트들과 거기서 참조가 일어나는 부분만 파악하면 그 뒤로는 객체 참조 필드를 쭉 타고가기만하면 되기 때문이고, 각 객체들은 헤더에 각자 클래스의 klass 구조체를 가리키는 포인터가 있기 때문에 그것을 확인하면 되기 때문이다.

 

아무튼 JIT컴파일러가 어디서 참조가 발생했는지 파악하면 OopMap에 이를 기록하게된다.

이런 과정을 통해서 가비지컬렉터는 메서드 영역과 다른 GC 루트들로부터 시작하여 스캔 과정에서 해당 메모리에 저장된 값이 참조값인지 원시값인지 알아낼 수 있다.

 

즉, 핫스팟은 JIT컴파일러가 스택의 어느 슬롯과 레지스터에서 참조가 발생하는지 클래스가 로딩될 때 형성된 klass 구조체를 확인해가며 OopMap에 기록을 남긴다. (많은 자바 기초 저서들이 '클래스는 객체의 설계도다'라고 하는데에는 이러한 이유가 있는듯하다.)

 

 

그래서 이 루트 노드 열거의 순서를 정리하자면

 

0. 클래스가 로딩될 클래스의 변수가 참조형인지 원시형인지 구분하는 정보를 담은 klass 구조체가 만들어진다.

 

1. JIT컴파일러는 스택의 어느 슬롯의 변수가, 아니면 어느 레지스터가 참조인지 OopMap이라는 자료구조에 저장한다. 아직 JIT컴파일러에 대해서 모르므로 메모리 내에서 어디가 참조형 변수가 저장되는지 파악한다고 보면 될 듯하다. JIT컴파일러는 애플리케이션 실행 중 여러 번 실행되고, 이 OopMap도 JIT컴파일러가 돌아갈 때 만들어지게된다.

 

2. 가비지컬렉션이 시작되면 가비지컬렉터는 모든 스레드를 멈추고 '루트 노드 열거'를 시작한다.

 

3. 이 '루트 노드 열거'는 GC루트에서 연결된 객체들과 연결되지 않을 객체들을 분석해 회수할 메모리를 고르는 도달 가능성 분석 알고리즘을 준비하는 과정이다. 

 

4. GC는 루트 노드 열거 과정에서 OopMap을 참고하여 GC루트에서 객체 참조가 이루어지고 있는 부분에만 접근한다.

 

5. 이후 객체 참조가 이루어지는 부분에서 호출된 각 객체에 접근하고, 그 객체의 헤더에 있는 klass 구조체를 읽어 그 객체가 참조하고 있는 다른 객체에 접근한다. 이 과정을 반복해서 GC루트로부터 연결된 객체들을 파악하고, 연결되지 않은 객체들은 가비지컬렉션의 대상으로 한다.

 

 

그리고 이중에서 2번부터 4번까지가 GC루트가 참조 중인 다른 객체를 찾는 과정인 루트 노드 열거에 해당한다. 그리고 5번 과정이 바로 도달 가능성 분석 알고리즘에 해당한다.

이그잭트VM부터 시작해 현재 핫스팟VM까지 가상머신의 가비지컬렉터는 이러한 과정을 통해서 도달 가능성 분석 알고리즘을 실행시킨다.

 

일련의 과정을 알았으므로 과거 클래식 VM과 다시 비교를해보자면,

클래식VM은 정확한 메모리 관리기술이 없었으므로 메모리에 저장된 값이 숫자값인지 참조값인지 알 수 없었다. 그래서 해당 값이 힙메모리 범위 내에 속한다면 모두 참조값으로 추정했다. 또한 자바 파일의 전체를 컴파일해서 시간도 오래걸렸고.

 

현재 VM은 파일 전체가 아니라 그때그때 필요한 부분만 컴파일한다. JIT컴파일러가 이 역할을 수행하며, 그렇기 때문에 시간도 줄고 현재 컴파일된 부분의 스택과 레지스터에서 참조가 되는 부분을 찾아서 참조체인을 찾는 과정으로 참조값과 숫자값을 구분하여 클래식 VM에 비해 시간도 줄고 정확성도 올라갔다.

 

 

그럼 여기서 의문이 드는데,

"왜 클래식 VM은 이러한 방식을 사용하지 않았을까?"라는 의문이 든다.

이 의문은 뒤에서 나올 '안전지점'에 대한 개념을 알아야하기 때문에 우선적으로는 현재 핫스팟 VM이 어떤 방식으로 루트GC에서 연결된 객체들을 확인해두고 저장하는지 알아두기만하면 좋을듯하다.

'CS > JVM' 카테고리의 다른 글

[JVM] JVM 내에서 카드테이블과 사전장벽, 사후장벽이란?  (1) 2026.01.01
[JVM] 가비지컬렉터는 어디에서 실행되어야하는가? - 안전지점(Safe Region)  (0) 2025.12.27
[JVM] JVM 끝까지 파헤치기 독서 #5 - 가비지 컬렉터의 알고리즘 이론  (0) 2025.12.26
[JVM] GC의 객체회수과정은 어떻게 일어나는가? - 마크-스윕, 마크-카피, 마크-컴팩트  (0) 2025.12.26
[JVM] 참조 카운팅 알고리즘과 파이썬의 순환 검출 알고리즘에 대해서  (0) 2025.12.25
'CS/JVM' 카테고리의 다른 글
  • [JVM] JVM 내에서 카드테이블과 사전장벽, 사후장벽이란?
  • [JVM] 가비지컬렉터는 어디에서 실행되어야하는가? - 안전지점(Safe Region)
  • [JVM] JVM 끝까지 파헤치기 독서 #5 - 가비지 컬렉터의 알고리즘 이론
  • [JVM] GC의 객체회수과정은 어떻게 일어나는가? - 마크-스윕, 마크-카피, 마크-컴팩트
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211) N
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59) N
        • JVM (12)
        • 백엔드 (20) N
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[JVM] OopMap으로 참조체인 내 속한 객체 찾기
상단으로

티스토리툴바