JVM과 가비지 콜렉터

민성재·2022년 4월 18일
0

JAVA의 특징

  1. 운영체제 독립적이다.
    • JAVA는 운영체제나 하드웨어와는 통신하지 않고, JVM과만 통신한다.
    • JVM은 운영체제 종속적이다.
    • JAVA는 한번만 작성되어도 어느 운영체제에서도 사용이 가능하다.
  2. 객체 지향 언어이다.
    • 특징 3가지(상속, 캡슐화, 다형성)
  3. 자동 메모리 관리를 해준다.
    • 가비지 컬렉터가 자동으로 메모리를 관리해준다. (그래서 메모리를 체크,반환하는 일을 해줄 필요가 없다)
  4. 네트워크와 분산처리를 지원한다.
    • 자바는 풍부하고 다양한 표준 라이브러리를 제공한다.
  5. 멀티쓰레드를 지원한다.
    • 관련 라이브러리를 제공한다.(JAVA API)
    • 여러 쓰레드에 대한 스케줄링은 자바 인터프리터가 담당한다.
  6. 동적로딩을 지원한다.
    • 작성한 자바 어플리케이션에 클래스가 여러개여도 모두 로딩하지 않고, 필요할 때마다 로딩하여 사용한다. 그래서 변경사항이 발생하여도 전체 어플리케이션을 다시 컴파일하지 않는다.

JVM의 메모리 구조

메소드 영역(method area)

  • 사용되는 클래스 파일(*.class) 정보(클래스 데이터)와 클래스 변수(class variable)가 이곳에 저장됨.
  • 클래스,인터페이스,메소드,필드,Static 변수등의 바이트 코드를 보관함.

힙 영역(heap)

  • 인스턴스가 생성되는 공간
  • 가비지 컬렉터가 참조되지 않는 메모리를 확인하고 제거하는 영역

호출 스택(call stack,execution stack)

  • 메소드 작업에 필요한 메모리 공간을 제공한다.
    • 메소드가 작업을 수행하는 동안 중간의 연산 결과등을 저장하는데 사용됨
  • 호출스택의 제일 위에 있는 메소드가 현재 실행중인 메소드이다.
  • 그 아래 메소드는 위 메소드를 호출한 메소드이다.

가비지 컬렉터(Garbage Collector)

Garbage Collection(GC)은 메모리 관리 기법 중 하나로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요없게 된 영역을 해제하는 기능으로, 1959년 존 매카시라는 사람이 개발하였다.

프로그램을 개발하다 보면 유효하지 않은 메모리인 가비지(Garbage)가 발생한다. c언어에서는 free()라는 함수로 직접 메모리를 해제해주지만 자바나 코틀린에서는 이럴 필요가 없다. JVM 안에 있는 가비지 콜렉터가 불필요한 메모리를 알아서 정리해주기 때문이다.
(System.gc()라는 메소드를 명시적으로 호출할 수는 있지만 시스템 성능에 큰 영향을 주므로 절대 호출하지 않는것이 좋다고 한다.)

JVM-based application’s working cycle

GC의 동작 방식은 2가지의 공통 단계를 따른다.

1. Stop The World

Stop The World 는 가비지 컬렉션을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 작업이다.
이때는 GC를 실행하는 쓰레드를 제외한 모든 쓰레드의 작업이 중단되며 GC가 완료되면 재개된다.
이 시간을 STW라고 하며 GC 성능개선을 하기 위해 보통 이 STW를 줄이려고 한다.

2. Mark and Sweep

Mark : 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업
Sweep : 마크 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업

Heap의 Generation

Heap 영역은 처음 설계될 때, 2가지를 전제로 설계되었다.

  • 객체는 금방 접근 불가능한 상태가 된다.
  • 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.

객체는 대부분 일회성이며, 메모리에 오랫동안 남아있는 경우는 드물다.

그래서 객체의 생존 기간에 따라서 물리적인 Heap 영역을 나누었는데, Young, Old 2가지 영역이 설계되었다.

  • Young Generation

    • Eden spaceSurvivor space 로 나누어진다.
    • 새로운 객체가 할당되는 곳.
    • 대부분의 객체가 이곳에서 사라진다.
    • 여기서 일어나는 가비지 콜렉션 GC를 minor GC라고 부름
    • 두가지 기술
      • bump-the-pointer
      • TLABs(Thread-Local Allocation Buffers)
  • Old Generation

    • Tenured space
    • 장기간 살아있는 객체가 저장되어진 곳.
    • 여기서 일어나는 가비지 콜렉션 GC를 major GC라고 부름

Minor GC 의 동작방식

1. 새로 생성된 객체가 Eden 영역에 할당된다.

2. 객체가 계속 생성되어 Eden 영역이 꽉차게 되고 Minor GC가 실행된다.

2-1)Eden 영역에서 사용되지 않는 객체의 메모리가 해제된다.
2-2)Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동된다.

3. 1~2번의 과정이 반복되다가 Survivor 영역이 가득 차게 되면 Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킨다.(1개의 Survivor 영역은 반드시 빈 상태가 된다.)

4. 이러한 과정을 반복하여 계속해서 살아남은 객체는 Old 영역으로 이동(Promotion)된다.

객체의 생존 횟수를 카운트하기 위해 Minor GC에서 객체가 살아남은 횟수를 의미하는 age를 Object Header에 기록한다. 그리고 Minor GC 때 Object Header에 기록된 age를 보고 Promotion 여부를 결정한다.

또한 Survivor 영역 중 1개는 반드시 사용이 되어야 한다. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 모두 사용량이 0이라면 현재 시스템이 정상적인 상황이 아님을 파악할 수 있다.

Major GC(Full GC)의 동작 방식

Young 영역에서 오래 살아남은 객체는 Old 영역으로 Promotion됨을 확인할 수 있었다. 그리고 Major GC는 객체들이 계속 Promotion되어 Old 영역의 메모리가 부족해지면 발생하게 된다. Young 영역은 일반적으로 Old 영역보다 크키가 작기 때문에 GC가 보통 0.5초에서 1초 사이에 끝난다. 그렇기 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않는다. 하지만 Old 영역은 Young 영역보다 크며 Young 영역을 참조할 수도 있다. 그렇기 때문에 Major GC는 일반적으로 Minor GC보다 시간이 오래걸리며, 10배 이상의 시간을 사용한다.

Java 8 이전에는 PermGen (Permanent Generation)이 존재하였음. 클래스나 메소드의 metadata를 저장하는 공간으로, old 영역에서 살아남은 객체가 저장되는 곳( Major GC가 일어남) 하지만, JAVA8 이후에는 Metaspace가 PermGen의 공간을 대체하게 되었다.

profile
민성재 개발 블로그

0개의 댓글