IT/개발(자바, 서블릿, 스프링 등)

[Java] 자바의 메모리 구조 정리

히유우 2019. 12. 7. 18:35

자바 프로그램은 JVM에 의해 실행된다. JVM은 자바 프로그램을 실행하면서 필요한 데이터를 메모리에 생성한 후에 사용한다. 이 때 메모리를 세가지 영역으로 구분하여 사용한다. Code 영역 / Heap 영역 / Stack 영역.

 

  • 코드 영역(메서드 영역)

클래스 파일을 실행하면 JVM의 클래스 로더가 클래스 파일을 실행하기 위해 필요한 클래스 파일을 메모리에 올린다. 자바 소스 파일에 정의한 클래스에 관한 정보와 코드를 코드 영역에 만들어준다.

 

  • 힙 영역

클래스를 설계하고 이를 사용하려면 메모리에 해당 클래스의 인스턴스를 생성해야 한다. new 명령문으로 인스턴스를 생성하면 메모리의 힙 영역에 생성된다. 그런데 클래스의 메서드는 실행 시작 시점에 클래스 로더에 의해 코드 영역에 만들어진다. 따라서 실제로 힙 메모리에 필드만 생성된다. 인스턴스가 가지고 있는 메서드는 코드 영역에 생성된다.

 

  • 스택 영역

필드는 클래스의 속성을 나타내는 변수이다. 지역변수는 메서드가 실행되면서 필요한 데이터를 잠시 유지하기 위해 사용하는 변수로 메서드 내에서 선언한 변수이다. 필드는 new 명령문에 의해 객체가 생성될 때 힙에 생성되지만, 지역변수는 메서드가 호출되어 실행될 때 스택에 생성이 된다. 지역변수가 스택에 생성되는 시점은 메서드가 호출되어 실행될 때이다. 메서드 실행 시 스택에 생성된 지역변수는 메서드의 실행이 종료될 때 스택에서 자동으로 삭제 된다. 소멸된다.

 

자바 프로그램은 힙 메모리에 직접 접근할 수 없다. 직접 접근할 수 있는 메모리는 오직 스택뿐이다. 따라서 자바에서는 스택 메모리에 참조변수를 선언하고 이 변수에 힙 메모리에 생성된 인스턴스의 참조 정보를 저장해서 접근하는 방식을 사용한다. 즉, new 명령문이 인스턴스를 힙 메모리에 할당할 때 반환하는 참조 정보를 변수에 저장해 사용함으로써 해당 인스턴스에 접근할 수 있다. 참조변수에는 할당된 메모리의 위치 정보가 저장된다.

 



class Calc {
    public int sum(int num1, int num2){
    	return num1+num2;
    }
}


public class CalcTest(){
	public static void main(String[] args){
    	Calc calc = new Calc();
        calc = null;
        calc.sum(1, 1);
	}
}

위의 소스코드를 실행하면 NullPointerException이 발생한다. 지역변수 calc에 null 값을 저장했기 때문이다. 자바에서 널은 '아무 값도 가지지 않는다'는 뜻이다. 이 때 힙에 생성된 Calc 인스턴스의 참조 정보를 스택에서 아무도 가지고 있지 않으므로 접근할 방법이 없다. 이런 상황을 참조가 끊겼다고 한다. 참조가 끊긴 인스턴스는 더이상 사용할 수 없고, 메모리만 낭비한다. 이렇게 가비지가 된 인스턴스들은 JVM의 가비지 콜렉션에 의해 메모리에 삭제된다.

 

* 필드 초기화

필드는 메모리에 생성된 후 자동으로 초기화되지만, 지역변수는 자동으로 초기화되지 않으므로 선언과 동시에 초기화 작업을 해야 한다. new 명령문으로 클래스의 인스턴스를 생성하면 해당 클래스에 선언한 필드가 힙 영역에 생성된다. 이때, 각 필드는 별도로 초기화하지 않아도 자동으로 초기화된다. 이때의 초깃값은 필드의 데이터 타입에 따라 다르다. 

 

 

필드 타입별 초깃값

필드 타입
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0D
char '\u0000'
boolean false
모든 참조변수 null