JVM의 메모리 구조

JP·2022년 1월 9일
0

자바

목록 보기
2/10

자바 프로그램이 실행되면 JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.

그 중 내가 알아 볼 것은
1. 스태틱 영역
2. 스택 영역
3. 힙 영역
이렇게 세가지이다.

스프링 입문을 위한 자바 객체지향의 원리와 이해(김종민)라는 책을 보면 각 영역을 아래와 같이 표현했다.

스태틱 - 클래스들의 놀이터

스택 - 메서드들의 놀이터

힙 - 객체들의 놀이터

그렇다면 각 영역에 대해 알아보자

스태틱 영역

  • 흔히 스태틱이라고 불리는 이 메모리 영역은 정적 메모리라는 뜻을 가지고 있다.
    - 이는 컴파일 시간동안 할당 된 메모리이며 고정된 공간을 차지하고 런타임 중에 변경할 수 없는 특징을 가지고 있다.
  • 클래스 멤버 변수는 스태틱 영역에서 일생을 보낸다.

스택 영역

  • 스택은 단어 그대로 쌓아 올린다는 뜻이다.
  • 프로그램 실행 중 어떤 클래스가 사용되면 JVM은 해당클래스의 클래스파일을 읽어서 분석하여 클래스에 대한 정보를 이곳에 저장한다.
  • 지역 변수는 스택프레임이 생성 되었을 때 생기고 사라질때 같이 지워진다.

힙 영역

  • 인스턴스가 생성되는 공간이다.
    - 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다.
    • 힙에 생성되는 객체의 주소는 스택 영역
  • 객체 멤버 변수는 힙에서 일생을 보낸다.
    - 객체 멤버 변수들은 객체와 함께 가비지 컬렉터라고 하는 힙 메모리 회수기에 의해 일생을 마치게 된다.

프로그램 내에서 메모리에 어떻게 데이터가 적재되는지 코드와 그림으로 알아보자.

public class Start{
	public static void main(String[] args){
    	System.out.println("this is java");
    }
}
  1. JRE는 먼저 프로그램 안에 main() 메서드가 있는지 확인한다.
    • main()메서드의 존재가 확인되면 JRE는 JVM을 실행시킨다.
  2. JVM이 가장 먼저 하는 일은 전처리라고 하는 과정이다
    • java.lang은 모든 자바프로그램이 반드시 포함하게 되는 패키지이다.
    • JVM은 가장 먼저 java.lang의 패키지를 스태틱 영역에 가져다 놓는다.
  3. JVM은 개발자가 작성한 모든 클래스와 임포트 패키지 역시 스태틱 영역에 가져다 놓는다.
    • 현재는 Start 클래스밖에 없다.
  4. main 메서드의 메서드를 여는 중괄호를 만나면 스택 영역에 main() 스택 프레임이 생성 된다.
  5. System.out.println("this is java") 구문을 실행하기 위해서는 메서드의 인자 args를 저장할 변수 공간을 스택 프레임의 맨 밑에 확보해야 한다.
    • 메서드 인자들의 변수 공간을 할당하는 것이다.
  6. main()메서드의 닫는 중괄호를 만나면 스택 프레임이 소멸된다

그렇다면 변수는 어디에 저장되는 것일까?

public class Penguin{
	public static void main(String[] args){
    	int num = 10;
        void walk(){
        	System.out.println("walk walk");
        }
    }
}

public class Start{
	public static void main(String[] args){
    	Penguin pororo = new Penguin();
        pororo.walk();
    }
}
  • 위의 코드를 풀어 나가면 JRE는 main()를 확인하고 존재한다면 JVM을 실행시킨다.
  • JVM은 가장 먼저 java.lang과 모든 클래스와 임포트 패키지를 스태틱 영역에 가져다 놓는다.
  • main 메서드의 메서드를 여는 중괄호를 만나면 스택 영역에 main() 스택 프레임이 생성 된다.
  • main스택 프레임 안에 Pororo 객체를 생성하는 코드가 있다
  • 그리고 walk()의 스택프레임이 생성되고 안의 로직이 실행된다.

스택 프레임은 닫는 중괄호를 만나면서 소멸되고 시스템의 자원을 운영체제에게 반납한다.

사용되지 않는 객체는?

위의 코드를 보면 스택 영역이 종료되면서 힙 영역에 있는 Pororo 객체를 더 이상 참조하지 않게 되었다는 걸 알 수 있을 것이다.

그렇다면 힙영역에 계속되어서 객체가 쌓이게 둘 것인가? 프로그래밍 랭귀지에서는 더 이상 쓰이지 않는 객체를 수거하기 위해 Automatic Garbage Collection이란 기술이 쓰인다.

오라클-가비지컬렉션
에서 가비지컬렉션을 어떻게 설명하고 있는지 보면

"Automatic garbage collection is the process of looking at heap memory, identifying which objects are in use and which are not, and deleting the unused objects"
Automatic garbage collection은 힙을 보는 프로세스로서 어떤 객체가 사용중에 있고 어떤 객체가 아닌지를 파악하여 사용되지 않는 것을 삭제 한다.

Java에서 메모리 할당 해제 프로세스(가비지컬렉션)는 가비지 컬렉터에 의해 자동으로 처리된다.

가비지 컬렉터는 아래의 순서로 작동한다
1. 마킹(marking)
- 안쓰이는 객체를 식별한다

2. 삭제(Deletion)
- 안쓰이는 객체를 삭제한다

3. 압축(Compacting)
- 삭제된 빈 공간을 압축한다

위의 과정을 반복하다보면 힙 영역에는 가비지 컬렉터를 피해 살아남은 객체들이 쌓이게 될 것이다.
이 군을 나눠보면 새로 생성된 것 + 생성된지 얼마 안된 것(Young), 살아남은지 오래된 것(Old) 그리고 영원히 살아남을 수 있는 객체(Permanent) 이렇게 세 가지 군이 존재할 것이다.

위의 그림에서 보면 eden은 새로 생성 된 것, S0S1은 생성된지 얼마 안된 객체로 구성된 Young Generation, Tenured는 종신형(오래 살아남은)을 받은 Old Generation, Permanent 는 영원히 살아남을 것 같은 객체 Permanent Generation으로 구분되어 있다.

이 곳에서 일어나는 일들은 순서대로
1. 새로운 객체는 eden에 할당된다.
2. eden 영역이 가득차게 되면 Minor Garbage Collection이 발생한다
3. Minor Garbage Collection이 발생하면 살아남은 객체들은 S0으로 이동된다.
- 위의 과정이 반복되면서 eden -> S0 -> S1 으로 이동 되고 age가 증가한다
4. S1에서 계속해서 가비지 컬렉터를 피해 살아남으면 age가 계속 오르게 되고 이러한 객체들은 Old Generation으로 이동한다.
- 이러한 이동을 Promotion(승진?) 이라고 한다.
5. 이렇게 해서 Old Generation 부분도 가득차게 되면 Major Garbage Collection이 발생한다


가비지 컬렉터가 무엇인지,
마킹과 삭제, 압축 의 과정
그리고 Young, Old, Permanent 객체들 사이에서 일어나는 garbage collection과 promotion 기타 등등의 정보를 얻을 수 있다.

profile
to Infinity and b

0개의 댓글