티스토리 뷰

최근에 Kotlin Coroutine을 공부하다 보니 Thread와 관련돼서 알아보게 되었고 JVM Memory에 관해서 다시 알아보다가 Baeldung에 최근에 올라온 글이 있어서 번역해보려고 합니다. 아래 목록을 참고하셔서 읽으시면 도움이 될 수 있습니다.

  • 기본적으로 제가 읽고 번역한 사항이고 부분적으로 Google 번역기를 이용하였습니다.
  • 원 글에서 Stack은 Memory로 표현했고 Heap은 Space로 표현했으나 둘 다 메모리 영역이고, Memory와 Space를 구분하는 게 무의미하여 Stack과 Heap으로만 표현했습니다.
  • 번역을 했으나 부자연스러운 부분은 물음표(?)로 표시해놓았으니 원글을 통해서 확인하시면 도움이 될 것 같습니다.

1. 들어가면서 (Introduction)

 Application을 효율적으로 구동하기 위해서 JVM 기기들은 메모리를 Stack과 Heap으로 구분해놓았습니다. 우리가 새로운 변수나 객체를 생성하거나, 함수를 호출하고 String 자료형을 선언하는 등의 행위를 할 때마다 JVM은 이를 수행하기 위해서 Stack이나 Heap의 메모리를 지정합니다.

 이 글에서는 이러한 메모리 형태에 대해서 알아보고자 합니다. 먼저 우리는 이들에 대한 주요사항들을 둘러볼 거예요. 그런 다음 메모리(RAM)에저장하는 방법과 사용처에 대해 알아볼거예요. 마지막으로는 서로의 차이점에 대해서도 설명해 볼 거예요.

2. Java에서의 Stack (Stack Memory in Java)

 Java에서의 Stack Memory(이하 Stack)는 정적인 할당과 스레드를 실행하는 데 사용됩니다. 이는 메서드에 배정된 primitive type 변수와 Heap Space(이하 Heap)에 있는 메서드에 의해 참조된 객체에 대한 참조값을 갖고 있습니다.

 Stack에 대한 접근은 후입선출(LIFO;Last-In-First-Out)로 작동합니다. 우리가 메서드를 호출할 때마다 primitive type 변수가 참조되는 객체와 같이 메서드에 할당된 값들을 갖고 있는 새로운 메모리 블럭이 스택의 상단에 생성됩니다.

 메서드가 실행을 완료하게 되면, 이에 상응하는 메모리가 반환(flush)되고 호출된 메서드로 흐름이 이동하게 되며, 이후 메서드들이 공간을 이용할 수 있게 됩니다.

2.1. Stack의 주요 내용 (Key Features fo Stack Memory)

 Stack에 대한 다른 내용들은 다음과 같이 있습니다.

  • 메서드가 호출되고 반환될 때마다 크기가 커지고 줄어듭니다.
  • 스택 내부의 변수는 변수를 생성한 메서드가 실행되는 동안에만 존재합니다.
  • 메서드 실행이 완료되면 자동으로 할당 해제됩니다.
  • Stack이 가득 차면 Java에서 java.lang.StackOverFlowError 예외를 발생시킵니다.
  • Heap에 비해 접근 속도가 빠릅니다.
  • 스레드는 각자의 스택에서 작동하므로 다른 스레드로부터 안전합니다.

3. Java에서의 Heap (Heap Space in Java)

 Heap은 런타임에 JRE 클래스들이나 Java 객체에 대해서 동적인 메모리 할당을 하는 데 사용됩니다. 새로운 객체는 항상 Heap에 생성되며 이 객체에 대한 참조값은 Stack에 존재합니다.

 Heap에 존재하는 객체는 전역적으로 접근 가능하여 Application의 어느 곳에서나 접근이 가능합니다.

 Heap은 더 작게 구분된 형태인 제너레이션(Generation)이 있습니다.

  1. Young Generation - 여기는 객체가 새로 생성되면 할당되어 저장됩니다. 만약 가득 차게 되면 소규모의(minor) Garbage collection이 발생합니다.
  2. Old or Tenured Generation - 여기는 오랫동안 살아남은 객체들이 저장되는 곳입니다. Young Generation에 객체가 저장될 때 객체의 수명에 대한 임계치(Threshold)가 설정되고, 그 임계치에 이르면 객체는 Old Teneration으로 이관됩니다.
  3. Permanent Generation - 이곳은 런타임 클래스들과 Application 메서드들의 JVM 메타데이터가 저장되어있습니다.

 이러한 차이점에 대해서는 Difference Between JVM, JRE and JDK 문서에서도 설명합니다.

3.1. Heap의 주요내용 (Key Features of Java Heap Memory)

 Heap에 대한 다른 내용들은 다음과 같이 있습니다.

  • Young Generation, Old or Tenured Generation, Permanent Generation을 포함하는 복합적인 메모리 관리 기술(Complex memory management techniqes)들에 의해 접근이 됩니다.(?)
  • 만약 Heap이 가득 차게 된다면 Java는 java.lang.OutOfMemoryError 예외를 발생시킵니다.
  • Heap에 접근하는 것은 Stack에 접근하는 것보다 상대적으로 느립니다.
  • Heap은 Stack과는 반대로 메모리가 자동으로 반환되지 않습니다. 메모리를 반환하기 위해서는 사용하지 않는 객체를 Garbage Collector가 반환해 줘야(free up) 합니다.
  • Stack과는 다르게 Heap은 스레드에 안전하지 않고(isn't threadsafe) 코드를 동기화(synchronizing)하는 값(property)에 의해 보호되어야 합니다. (의역) threadsafety 하지 않아서, 코드 수준에서 동기화하는 데 있어서 고려해야합니다.

4. 예제 (Example)

 지금까지 배운 것들에 기반하여 어떻게 메모리를 관리하는지에 대해 알아보는 간단한 Java 코드를 분석해 볼 것입니다.

class Person {
    int id;
    String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class PersonBuilder {
    private static Person buildPerson(int id, String name) {
        return new Person(id, name);
    }

    public static void main(String[] args) {
        int id = 23;
        String name = "John";
        Person person = null;
        person = buildPerson(id, name);
    }
}

 차근차근 코드를 분석해 볼까요?

  1. main() 함수에 진입하게 되면 Stack 안에 privitive type 변수와 메서드에 대한 참조를 저장하기 위해 공간이 생성됩니다.
    • Stack은 정수값 id의 primitive type 값을 직접적으로 저장합니다.
    • Person 자료형인 객체 person에 대한 참조값은 Stack에 저장되며 이 값은 실제로 Heap 안에 있는 객체를 가리킵니다.
  2. main()에서 Persion(int, String) 생성자를 호출하면, Stack의 상단에 추가적인 메모리가 할당되며 아래 내용을 저장합니다.
    • Stack에서 호출하는 객체에 대한 this 객체 참조
    • Stack 안에 있는 primitive type 값인 id
    • 값 참조 변수인 name(String)은 Heap 안에 있는 문자열 pool에 있는 실제 문자열을 가리킬 것입니다.
  3. main() 함수는 추가적으로 정적 메서드인 buildPerson()을 호출하고 있고, 이를 위해 추가적인 할당을 Stack의 상단에 할 것입니다. 이후 위에서 설명한 방식으로 변수가 다시 저장됩니다.
  4. 반면에 Heap은 새로 생성되는 Person 타입의 person 객체의 모든 인스턴스 변수들을 저장할 것입니다.

 아래 다이어그램에 있는 할당 과정을 봅시다.

5. 요약 (Summary)

Parameter Stack Heap
Application Stack is used in parts, one at a time during execution of a thread The entire application uses Heap space during runtime
Size Stack has size limits depending upon OS, and is usually smaller than Heap There is no size limit on Heap
Storage Stores only primitive variables and references to objects that are created in Heap Space All the newly created objects are stored here
Order It's accessed using Last-in First-out (LIFO) memory allocation system This memory is accessed via complex memory management techniques that include Young Generation, Old or Tenured Generation, and Permanent Generation.
Life Stack memory only exists as long as the current method is running Heap space exists as long as the application runs
Efficiency Much faster to allocate when compared to heap Slower to allocate when compared to stack
Allocation/Deallocation This Memory is automatically allocated and deallocated when a method is called and returned, respectively Heap space is allocated when new objects are created and deallocated by Gargabe Collector when they're no longer referenced

6. 마무리하면서 (Conclusion)

 스택과 힙은 Java가 메모리를 할당하는 두 가지 방법입니다. 이 글에서는 작동 방식과 더 나은 Java 프로그램 개발을 위해 사용하는 경우를 배웠습니다.

 Java의 메모리 관리에 대해 자세히 알아보려면 여기에서 이 글을 살펴보십시오. 또한 이 문서에서 간략하게 설명하는 JVM Garbage Collector에 대해서도 다루었습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함