Study/Java

자바 기본서를 다시 읽다. 1-JVM의 메모리 사용 영역

going.yoon 2022. 3. 10. 22:15

 

Java 기본서를 다시 읽으려고 한다. 이펙티브 자바를 공부하기 전 빠르게 완독하려 핀 책이었으나, 기본기가 꽤나 듬성듬성 비어있더랬다.

지식의 구멍을 메우고 기초를 탄탄히 하자는 마음에서 다시 자바 기본서를 공부해보려 한다. 내가 선택한 책은 '이것이 자바다(신용권)'의 책이다. 기존에 가지고 있던 기본서는 'Introduction to Java Programming(Liang)'이라는 원서였는데 자바 8의 함수형 인터페이스와 스트림 등이 반영되어있지 않아 이 책을 선택하게 되었다. 자바 8 관련 내용을 제외하고는 헷갈렸던 부분을 빠르게 짚고 넘어가려고 한다.

 

 

   그 첫번째로 JVM과 메모리 사용 영역에 대해 알아보자. 자바는 운영체제에서 바로 실행될 수 없는 언어이다. 자바 프로그램은 완전한 기계어가 아닌 중간 단계의 바이트 코드이기 때문에 이것을 해석하고 실행할 수 있는 가상의 운영체계(JVM)이 필요하다. 이 JVM은 자바를 중계하는 가상의 운영체제 역할을 하는데 이는 운영체제에 종속적이다. 운영체재에 맞는 JRE나 JDK를 설치하면 자동으로 운영체제에 맞는 JVM이 설치된다.

 

 cf) JRE와 JDK의 차이점 : JRE는 Java Runtime Enviornment로, 자바를 실행하기 위한 환경이고 JDK는 Java Development Kit로 자바를 개발하기 위한 JRE + 개발 및 컴파일을 위한 도구이다. ( https://developerntraveler.tistory.com/49 )

 

 

I. JVM의 Runtime Data Area

Java가 JVM을 통해 이식되는 과정은 다음과 같다. 

 

그리고 노란색으로 색칠된 Runtime Data Area는 아래와 같은 구조로 메모리를 관리한다.

메소드 영역에서는 클래스 로더가 로드해주는 영역으로 JVM이 시작할 때 생성되고 모든 스레드가 공유한다. 런타임 상수풀, 필드 /메소드 데이터, 메소드 코드, 생성자 코드 등을 분류해서 저장한다. 정적 메소드와 정적필드는 클래스에 고정된 멤버로 클래스가 로딩되면 바로 메소 드영역에 적재되기 때문에 로딩 후 바로 사용 가능하다.

 

힙 영역은 배열과 객체가 생성되는 영역으로 JVM의 스택 내의 변수나 다른 객체의 필드에서 참조한다. 아무도 참조를 하지 않으면 가비지 컬렉터가 쓰레기 객체를 힙 영역에서 자동으로 제거한다.

 

스택영역은 스레드가 생성될 때마다 할당되며 메소드가 하나씩 호출될 때 마다 프레(Frame)이 추가된다. 이 프레임 내부에는 로컬 변수 스택이 있는데, 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거된다.

 

변수의 타입에 따른 메모리 저장 영역은 다음과 같다.

  • 원시 타입 ( Primitive Type ) : 값이 스택에 직접 저장된다.
  • 참조 타입 ( Referenced Type ) : 값이 에 직접 저장된다. 스택에는 힙의 주소를 저장해서 원본 데이터를 참조한다.
  • 문자열 ( String ) : 값이 에 직접 저장된다. 다만 리터럴이 동일한 객체가 생성될 경우, 동일한 객체를 참조한다( 스택에서 동일한 힙 주소를 저장한다). cf ) new 연산자로 신규 객체 생성시는 제외

 

 

II. 메소드 영역과 Static

정적 메소드와 정적 필드는 클래스 로더에 의해 클래스 로딩이 되면 바로 메소드 영역에 적재가 된다고 했다. 그렇기 때문에 인스턴스 생성 없이 . 연산자로 직접 접근이 가능하다. 

public class FeeCalculator {
    static double feeIrt = 1.4; // #1. static 변수 선언
    static double getFee( int amt ){ // #2. static method
        return amt * feeIrt;
    }
}

public class Main {

    public static void main (String args[]){
        int amt  = 10000;
        
        // 인스턴스를 생성하지 않고 클래스의 메소드와 변수에 직접 접근이 가능하다.
        System.out.println("feeIrt : " + FeeCalculator.feeIrt); 
        System.out.println("fee : " + FeeCalculator.getFee(amt)/100);
    }
}

결과값

이렇듯 static은 인스턴스가 없어도 실행할 수 있기 때문에 객체 자신의 참조인 this 키워드도 사용이 불가능하다. 

static 변수에 this키워드 사용시 오류 출력