ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JVM의 메모리 영역에 대한 이해와 예시와 reflection의 이해
    자바웹프로그래밍/JAVA 2024. 7. 11. 13:52
    728x90
    반응형

     

     

     

    JVM의 메모리 영역은 각각의 역할이 있으며, 이를 이해하는 것은 Java 프로그램의 실행 방식을 이해하는 데 중요합니다. 각 메모리 영역의 역할과 이를 설명하기 위한 예제를 살펴보겠습니다.

     

    JVM 메모리 영역

    1. PC 레지스터 (Program Counter Register): 현재 실행 중인 JVM 명령의 주소를 가리킵니다. 각 스레드는 자신의 PC 레지스터를 가지고 있습니다.
    2. Java 스택 (Java Stack): 메서드 호출과 관련된 정보를 저장합니다. 각 스레드는 자신의 스택을 가지고 있으며, 각 스택 프레임은 메서드 호출, 지역 변수, 매개 변수, 그리고 연산 중간 결과를 포함합니다.
    3. 네이티브 메서드 스택 (Native Method Stack): 네이티브 메서드 호출과 관련된 정보를 저장합니다. 네이티브 메서드는 C나 C++로 작성된 메서드입니다.
    4. 힙 (Heap): 모든 객체와 배열이 저장되는 공간입니다. 모든 스레드가 공유하는 영역입니다.
    5. 메서드 영역 (Method Area): 클래스 메타데이터, 정적 변수, 그리고 런타임 상수 풀(Runtime Constant Pool)을 포함합니다. 모든 스레드가 공유하는 영역입니다.

    예제 코드

    간단한 예제를 통해 각 메모리 영역의 역할을 설명해보겠습니다.

     

    public class MemoryExample {
        private static int staticVariable = 5; // 메서드 영역에 저장
    
        private int instanceVariable; // 힙에 저장
    
        public MemoryExample(int value) {
            this.instanceVariable = value;
        }
    
        public static void main(String[] args) {
            int localVariable = 10; // Java 스택에 저장
    
            MemoryExample example = new MemoryExample(localVariable); // 힙에 저장
    
            example.display(); // 메서드 호출
        }
    
        public void display() {
            int anotherLocalVariable = instanceVariable + staticVariable; // Java 스택에 저장
            System.out.println("Result: " + anotherLocalVariable);
        }
    }

     

     

    각 메모리 영역의 역할 설명

    1. PC 레지스터:
      • JVM 명령을 실행하면서 현재 실행 중인 명령의 주소를 저장합니다.
      • 각 스레드는 고유의 PC 레지스터를 가집니다.
    2. Java 스택:
      • 메서드 호출 시마다 새로운 스택 프레임이 생성됩니다.
      • main 메서드가 호출되면 main 스택 프레임이 생성되고, localVariable이 여기에 저장됩니다.
      • example.display()가 호출되면 새로운 스택 프레임이 생성되고, anotherLocalVariable이 여기에 저장됩니다.
    3. 네이티브 메서드 스택:
      • 네이티브 메서드가 호출될 때 사용됩니다.
      • 이 예제에서는 네이티브 메서드가 없으므로 사용되지 않습니다.
    4. :
      • 모든 객체와 배열이 저장됩니다.
      • new MemoryExample(localVariable) 호출 시, 새로운 MemoryExample 객체가 힙에 생성되고 instanceVariable이 이 객체에 저장됩니다.
    5. 메서드 영역:
      • 클래스 메타데이터, 정적 변수, 런타임 상수 풀을 포함합니다.
      • staticVariable은 메서드 영역에 저장됩니다.
      • MemoryExample 클래스의 메타데이터 또한 여기에 저장됩니다.

    실행 과정 예시

    1. 프로그램 시작:
      • main 메서드가 호출되고, main 스택 프레임이 생성됩니다.
      • PC 레지스터는 main 메서드의 첫 번째 명령을 가리킵니다.
    2. 변수 초기화:
      • localVariable이 main 스택 프레임에 저장됩니다.
      • new MemoryExample(localVariable) 호출 시, 힙에 MemoryExample 객체가 생성되고, instanceVariable이 초기화됩니다.
    3. 메서드 호출:
      • example.display() 호출 시, 새로운 스택 프레임이 생성되고, anotherLocalVariable이 스택 프레임에 저장됩니다.
      • PC 레지스터는 display 메서드의 첫 번째 명령을 가리킵니다.
    4. 결과 출력:
      • System.out.println("Result: " + anotherLocalVariable); 명령이 실행되어 결과가 출력됩니다.

     

     

     

    JavaReflection

     

    Java Reflection API는 메서드 영역에 저장된 클래스 메타데이터를 사용하여 런타임에 클래스의 구조와 동작에 대해 정보를 가져옵니다. 메서드 영역에는 클래스의 구조적 정보(메서드, 필드, 인터페이스, 상속 관계 등)와 관련된 메타데이터가 저장되어 있으며, Reflection API는 이 정보를 액세스하고 조작할 수 있게 해줍니다.

     

     

    Reflection을 사용한 예제

    아래 예제는 Reflection을 사용하여 MemoryExample 클래스의 메타데이터를 가져와 출력하는 코드입니다.

     

    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class ReflectionExample {
        public static void main(String[] args) {
            try {
                // MemoryExample 클래스 타입 가져오기
                Class<?> memoryExampleClass = Class.forName("MemoryExample");
    
                // 클래스 이름 출력
                System.out.println("Class Name: " + memoryExampleClass.getName());
    
                // 필드 정보 출력
                Field[] fields = memoryExampleClass.getDeclaredFields();
                System.out.println("Fields:");
                for (Field field : fields) {
                    System.out.println(" - " + field.getName() + " of type " + field.getType());
                }
    
                // 메서드 정보 출력
                Method[] methods = memoryExampleClass.getDeclaredMethods();
                System.out.println("Methods:");
                for (Method method : methods) {
                    System.out.println(" - " + method.getName());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

     

    MemoryExample 클래스

     

    public class MemoryExample {
        private static int staticVariable = 5; // 메서드 영역에 저장
        private int instanceVariable; // 힙에 저장
    
        public MemoryExample(int value) {
            this.instanceVariable = value;
        }
    
        public static void main(String[] args) {
            int localVariable = 10; // Java 스택에 저장
            MemoryExample example = new MemoryExample(localVariable); // 힙에 저장
            example.display(); // 메서드 호출
        }
    
        public void display() {
            int anotherLocalVariable = instanceVariable + staticVariable; // Java 스택에 저장
            System.out.println("Result: " + anotherLocalVariable);
        }
    }

     

     

    실행 결과

    위의 코드를 실행하면 MemoryExample 클래스의 메타데이터가 출력됩니다. 예를 들어:

     

    Class Name: MemoryExample
    Fields:
     - staticVariable of type int
     - instanceVariable of type int
    Methods:
     - main
     - display
     - MemoryExample

     

     

    설명

    • Class.forName("MemoryExample"): MemoryExample 클래스의 Class 객체를 얻습니다. 이 객체는 메서드 영역에 저장된 메타데이터를 참조합니다.
    • memoryExampleClass.getName(): 클래스의 이름을 가져옵니다.
    • memoryExampleClass.getDeclaredFields(): 클래스에 선언된 모든 필드를 가져옵니다.
    • memoryExampleClass.getDeclaredMethods(): 클래스에 선언된 모든 메서드를 가져옵니다.
    728x90
    반응형
Designed by Tistory.