[Java] 메모리 구조 메소드(Method), 스택(Stack), 힙(Heap) 영역에 대하여

자바뿐만이 아니라 모든 프로그램이 구동되기 위해서는 프로그램 구동시에 운영체제로부터 메모리(RAM) 공간을 할당받아야 합니다. 이러한 메모리는 무제한이 아니라 한정되어 있습니다. 그렇기에 한정된 메모리를 최대한 효율적으로 사용하는 프로그램을 작성해야 하고 프로그램을 잘못 작성하게되면 프로그램이 매우 느려진다던지, 프로그램이 갑자기 꺼지는등의 각종 문제가 발생할 수 있습니다. 자바로 만들어진 프로그램은 JVM을 통해 실행되고 이 JVM은 프로그램을 동작할 때 OS로부터 메모리를 할당합니다. 

 

JVM에 대해서 좀 더 자세히 알고 싶다면 아래 글을 참고해주세요.

[Java] 자바 가상머신 JVM(Java Virtual Machine) 총정리

[Java] 자바 JVM 내부 구조와 메모리 구조에 대하여

 

 자바 메모리 구조 

메소드(Method) 영역

Static 영역이라고도 하며 전역 변수와 정적 멤버변수(static 변수)가 저장되는 영역입니다.

 

스택(Stack) 영역

지역변수, 인자값, 리턴값이 저장되는 영역이고 메소드 안에서 사용되는 기본형 변수들이 값과 함께 저장되고 Heap 영역에 생성된 객체들을 참조하는 주소값이 할당됩니다.

 

힙(Heap) 영역

자바 프로그램에서 사용되는 모든 인스턴스 변수(객체)들이 저장되는 영역이며 자바에서는 new를 사용하여 객체를 생성하면 힙 영역에 저장됩니다. 힙 영역은 메모리 공간이 동적으로 할당되고 해제되며 메모리의 낮은 주소에서부터 높은 주소로 할당이 이루어집니다.

 

 

 

멀티 스레드에서 메모리는 어떻게 사용되어지는가?

멀티 스레드에서 메모리 영역을 살펴보자면 메소드 영역과 힙 영역은 모든 스레드가 같이 공유하는데 반해 스택의 경우에는 각 스레드별로 하나씩 생성되어집니다. 이러한 특성으로 각 스레드마다 스택 메모리는 다른 스레드에서 접근이 불가능한 반면에 Method Area와 Heap Area는 모든 스레드에서 접근이 가능하고 프로그램의 시작부터 종료 될 때까지 메모리에 남아 프로그램이 실행되고 있다면 어디서든지 사용이 가능합니다. 이것이 전역변수는 어디서든 접근할 수 있고, Heap 영역의 객체를 주기적으로 삭제해주어야 하는 이유가 됩니다. 

 

스택(Stack)과 힙(Heap)에 대한 이해

먼저 Heap 영역에는 모든 Object 타입(Integer, String)등이 생성됩니다. 그리고 Heap 영역에 할당 된 Object 타입의 참조를 위한 값들이 Stack 영역에 할당됩니다. 또한 Stack에는 기본타입 변수들(int, double 등)이 실제 값과 함께 저장됩니다.

class Employee {
    String name;
    Integer salary;
    Integer sales;
    Integer bonus;

    public Employee(String name, Integer salary, Integer sales) {
        this.name = name;
        this.salary = salary;
        this.sales = sales;
    }
}

public class Test {
    static int BONUS_PERCENTAGE = 10;

    static int getBonusPercentage(int salary) {
        int percentage = salary * BONUS_PERCENTAGE / 100;
        return percentage;
    }

    static int findEmployeeBonus(int salary, int noOfSales) {
        int bonusPercentage = getBonusPercentage(salary);
        int bonus = bonusPercentage * noOfSales;
        return bonus;
    }

    public static void main(String[] args) {
        Employee john = new Employee("John", 5000, 5);
        john.bonus = findEmployeeBonus(john.salary, john.sales);
        System.out.println(john.bonus);
    }
}

예를 들어 위와 같은 소스코드가 있다면 아래의 영상과 같이 Stack과 Heap에 데이터들이 적재됩니다.

 

  • 모든 함수 호출은 스레드의 스택 메모리에 프레임 블록으로 추가됩니다.
  • 인수 및 반환 값을 포함한 모든 지역 변수는 스택의 함수 프레임 블록 내에 저장됩니다.
  • 같은 모든 기본 유형 int은 스택에 직접 저장됩니다.
  • Employee, Integer, 같은 모든 객체 유형 String은 힙에서 생성되며 스택 포인터를 사용하여 스택에서 참조됩니다. 이것은 정적 필드에도 적용됩니다.
  • 현재 함수에서 호출된 함수는 스택의 맨 위에 푸시됩니다.
  • 함수가 반환되면 해당 프레임이 스택에서 제거됩니다.
  • 메인 프로세스가 완료되면 힙의 객체는 스택에서 더 이상 포인터를 갖지 않고 고아가 됩니다.
  • 명시적으로 복사본을 만들지 않는 한 다른 개체 내의 모든 개체 참조는 포인터를 사용하여 수행됩니다.

댓글

Designed by JB FACTORY