Java Memory(Runtime Data Area) - GANGNAM-JAVA/JAVA-STUDY GitHub Wiki

Runtime Data Area

Runtime Data Area는 JVM이 프로그램을 수행하기 위해 OS로부터 할당받는 메모리 영역이다.

WAS의 성능에 문제가 발생했을 때, 대부분 이 영역들이 원인이 된다.(Memory Leak 혹은 GC)

Runtime Data Area는 5가지로 구분된다.

  • PC Register
  • JVM stack
  • Native Method stack
  • Heap
  • Method Area

위 그림에서 볼 수 있다시피, 위 3개의 영역은 Thread별로 생성되고, 아래 2개의 영역은

모든 Thread가 공유한다.

PC Register (Thread별로 1개씩 존재)

Java의 PC Register는 CPU 내의 기억장치인 레지스터와는 다르게 작동한다.

(Register-Base가 아닌 Stack-base로 작동)

현재 수행 중인 JVM Instruction 의 주소를 가진다

JVM stack (Thread별로 1개씩 존재)

Thread의 Method가 호출될 때 수행 정보(메소드 호출 주소, 매개 변수, 지역 변수, 연산 스택)가

Frame 이라는 단위로 JVM stack에 저장된다. 그리고 Method 호출이 종료될 때 stack에서 제거된다.

Native Method stack (Thread별로 1개씩 존재)

Java 외의 언어로 작성된 네이티브 코드들을 위한 stack

(ex JNI를 통해 호출되는 C/C++ 등의 코드)

Heap (모든 Thread가 공유)

인스턴스와 배열이 동적으로 생성되는 공간.

그리고 Garbage Collection의 대상이 되는 영역.

개발자는 객체를 제거하기 위해 별도의 코드를 작성할 필요가 없고 오히려 부작용만 낳을 가능성이 큼.

모든 Thread가 공유하기 때문에 동기화 문제가 발생할 수 있다.

Method Area (모든 Thread가 공유)

Class Loader가 적재한 클래스(또는 인터페이스)에 대한 메타데이터 정보가 저장된다.

이 영역에 등록된 class만이 Heap에 생성될 수 있다.

사실 Method Area는 논리적으로 Heap에 포함된다.

더 구제적으로는 Heap의 PermGen이라는 영역에 속한 영역인데, Java 8 이후로는

Metaspace라는 OS가 관리하는 영역으로 옮겨지게 된다.

Type Information
- Type(class or interface)의 전체 이름
- Type의 직계 하위 클래스 전체 이름
- Type의 class/interface 여부
- Type의 modifier (public / abstract / final)
- 연관된 interface 이름 리스트

Field Information
- Field Type
- Field Modifier (public / private / protected / static / final / volatile / transient)

Method Information
- Constructor를 포함한 모든 Method의 메타 데이터를 저장

Runtime Constant Pool
- Type, Field, Method로의 모든 레퍼런스를 저장
- JVM은 이 영역을 통해 실제 메모리 상의 주소를 찾아 참조

Class Variable
- static 키워드로 선언된 변수를 저장
- 기본형이 아닌 static 변수는 레퍼런스 변수만 저장되고 실제 인스턴스는 Heap에 저장됨
- 클래스를 사용하기 이전에 이 변수들은 미리 메모리를 할당받음

질문 1 :: Java heap memory 주소값으로 인스턴스의 접근이 가능할까?

불가능하다. 개발자는 객체의 주소를 직접적으로 지정할 수 없다.

오직 간접적으로만 할 수 있다.

예를들어, String str = "hello"; 코드를 보면 "hello" 문자열의 메모리 주소가

str에 할당되고 있다. 이제 str은 메모리 주소를 갖게 된다.

그리고 String str2 = str; 코드를 보면 str이 가리키고 있는 주소가 str2

할당되고 있다. "hello"라는 인스턴스를 복사하는 것이 아닌 "hello"의 주소를 복사하여

할당하는 것이다. 그러나 메모리 주소를 참조 변수에 직접 할당할 수는 없다.

왜냐하면 실제 주소를 알 수 없기 때문이다. JVM만이 객체가 메모리에 저장되어 있는 위치를

알고 있으며, 할당 작업을 실행하는 동안 해당 주소를 변수에 할당한다.

참조 변수에 직접 지정할 수 있는 주소는 null 뿐이다.

원문

You cannot assign the address of an object directly. You can only do so indirectly.
For example, in statement the 'String str = "hello";' you are assigning the address of 
the memory location at which the string "hello" is stores to str variable.
str, therefore, now contains the address of a memory location.

Similarly, in statement 'String str2 = str;' you are assigning the value stored in str 
to str2. You are not copying "hello" to str2. You are just copying the address stored 
in str to str2.

You cannot assign a memory address to a reference variable directly because you don't know 
the actual address. Only the JVM knows where an object is stored in memory and it assigns 
that address to the variable while executing the assignment operation. The only "address" 
you can assign to a reference variable directly is null.

질문 2 :: 그러면 왜 JVM만이 객체가 메모리에 저장되어 있는 위치를 알 수 있을까?

자바에선 변수의 메모리 주소를 얻는 것은 무의미하다.

왜냐하면 JVM은 자유롭게 객체를 구현하고, GC를 이용해 그 객체의 위치를 이동시키기 때문이다.

JVM만이 정확한 메모리 주소를 알고있다.

원문

Getting the memory addresses of variables is meaningless within Java, since the JVM is 
at liberty to implement objects and move them as it seems fit 
(your objects may/will move around during garbage collection etc.)