Programming Language/Java

자바(Java)와 메모리(Static, Stack, Heap)에 대한 정리

TwinParadox 2020. 10. 31. 11:25
728x90

코드를 조금 더 실용적으로 작성하기 위해선 JVM의 메모리 영역들에 대한 이해가 필요하다. 모든 것을 다 Heap이나 Stack에 밀어 넣고 인스턴스 생성과 Thread Safe에 대해 고려하지 않는 등의 행위는 적절하지 않기 때문이다. 메모리 영역에 대한 이해와 그를 바탕으로 한 코드 설계는 개발자가 더 나은 코드를, 그로 인해 더 나은 개발자가 되기 위해서는 필수적이다.

 

 

 메모리 구조

 

세부적으로 따지면 코드 영역 같은 것도 있고 하지만, 크게 이렇게 다루고 신경써줘야 하는 부분은 static, stack, heap이다. 각 영역마다 특징적인 것들이 있고, 그렇다 보니 그 특징들을 고려해서 코드를 작성해야 인스턴스의 불필요한 생성을 방지하고, Thread Safe를 보장할 수 있으니 잘 짚고 넘어가는 것이 필요하다.

 

 

static

  • 패키지나 클래스 정보가 호출되는 시점에 올라간다.
  • static이 붙은 클래스 멤버(필드, 메소드)도 이 영역에 올라간다.
  • static을 붙일 대상은 읽기 전용이 아닌 경우, 가능한 사용하지 않아야 하고 무분별하게 사용하면 멀티스레드에서의 Thread Safe 문제가 발생할 수 있다.
  • 클래스, 메소드 영역이라고도 불린다.
  • JVM 종료 시점까지 사라지지 않고 유지된다.

 

stack

  • 흔히 말하는 call stack이 이 영역에서 다뤄지는 내용이다.
  • stack에서 선언된 지역변수는 stack에 위치한다.
  • primitive는 stack 영역에 저장되고 reference(wrapper 등)는 참조값만 저장된다.
  • 외부의 stack frame에서는 내부 stack frame 변수 접근이 불가능하지만 내부에서 외부로는 가능하다.
  • 스레드도 stack 영역에 생성되며, 1개의 스레드는 별개의 T Memory(static, stack, heap)을 갖게 된다. 이로 인해서 하나의 스레드는 다른 스레드로 접근 불가능하지만, static과 heap은 공유해서 사용할 수 있다.
  • 위 특징으로 인해 멀티 스레드 구조가 멀티 프로세스보다 메모리를 적게 사용한다.

 

heap

  • 생성된 인스턴스들이 올라간다.
  • 인스턴스의 필드는 heap에 올라가고, 이로 인해서 static 메소드에서 인스턴스 멤버를 접근할 수 없다. 대상이 어떤 것인지도 모르고, 존재하지 않을 수도 있기 때문에.
  • 메소드들은 static이 아니어도 heap에 생기지 않는다.
  • stack 영역에서 참조값을 이용해 참조형 변수가 이 영역의 인스턴스를 제어할 수 있다.
  • 이 영역에 있는 인스턴스에 어떤 참조 변수도 참조하지 않으면 GC에 의해 제거된다.
  • 상속을 이용해 인스턴스를 생성하면, 상위 클래스들(Object까지)의 인스턴스도 같이 생성한다.

 

 

그러면 멀티 스레드에서는 어떻게?

멀티 스레드에서의 메모리 구조

멀티 스레드는 스택 영역에 대해서 스레드의 수만큼 분할해서 사용한다. 그렇기 때문에 하나의 메모리 구조에서 stack 영역만 나눠서 쓰는 구조고, 하나의 스레드에서 다른 스레드의 stack 영역은 접근하지 못하는 특성을 이용해서 Thread Safe를 확보한다.

 

 

멀티 프로세스의 메모리

잠깐 언급만하고 넘어가자면, 멀티 프로세스는 3개 영역에 대한 메모리를 프로세스가 각각 가져가기 때문에, 프로세스 별 고유 메모리 영역이 있으니까 프로세스 사이에서 참조할 수 없다. 이건 기본적으로 프로세스와 스레드의 차이를 알고 있다면 당연한 부분이다. 다만, 멀티 프로세스 구조 상 멀티 스레드보다는 더 큰 메모리를 차지한다.

 

Thread Safe

작업 수행 중 여러 스레드가 공유하는 특정 클래스의 인스턴스 상태가 변경될 가능성이 있는 경우 해당하는 경우 Thread Safe하지 않다고 이야기하는데, 꽤나 골치 아프게 작용할 수 있는 부분이라 멀티 스레드를 사용하는 경우 세심하게 신경 써야 한다. 

앞선 내용들을 잘 생각해보고, 인스턴스 필드를 선언해놓고 메소드에서 참조해서 사용하는 경우와 인스턴스 필드에 두지 않고 메소드 내부에서 선언해서 사용하는 경우 어떤 것이 Thread Safe를 보장하는지에 대한 내용을 따져보는 것을 추천한다. 메모리 영역에 대해 조금만 더 생각해보면 쉽게 답이 나온다.

 

 

 

Reference

www.geeksforgeeks.org/java-memory-management/

www.geeksforgeeks.org/how-many-types-of-memory-areas-are-allocated-by-jvm/

siyoon210.tistory.com/124

covenant.tistory.com/139

juneyr.dev/java-things

gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

728x90