서론
자바 공부를 하면서 객체는 어디에 저장이되고 Java언어로 작성된 프로그램은 어떻게 실행되는지 다시 한 번 개념을 잡고 가면 좋을거 같다라는 생각이 들어 공부하였고 다시 나만의 언어로 정리를 해보았다.
본론
JVM(Java Virtual Machine)
JVM(Java Virtual Machine)의 약자로 자바 가상 머신이라고도 말한다. JVM은 자바 프로그램을 효율적으로 실행하기 위해 만들어진 소프트웨어로 여러 구성 요소로 이루어져있다.
JVM 구성 요소
- 클래스 로더 :
- 자바 클래스 파일을 로드하고 바이트 코드를 메모리에 적재하여 JVM 이해할 수 있는 형태로 변환한다.
- 런타임 데이터 영역 :
- 자바 프로그램이 실행되는 동안 데이터를 저장하고 관리하는 메모리 영역이다.
- 실행 엔진 :
- 바이트 코드를 실제로 실행하는 부분이다. 인터프리터와, JIT 컴파일러를 이용하여 기계어로 변환한다.
- 네이티브 인터페이스 :
- 자바 프로그램이 C 와 C++ 와 상호작용할 수 있도록 지원한다.
- 가비지 컬렉터 :
- 더 이상 사용되지 않는 객체를 찾아 자동으로 제거해준다.
JVM 동작 방식
자바에서는 소스 코드를 직접 실행할 수 없다. 자바 컴파일러를 통하여 바이트 코드라는 중간 코드로 변환하고 이 코드를 JVM이 읽어 기계어로 변환하여 실행한다.
- 소스 코드 작성
- 사용자가 .java 확장자를 가진 소스 코드 파일을 작성한다.
- 컴파일
- 자바 컴파일러가 Java언어로 작성된 .java 파일를 읽어 바이트 코드 .class 로 변환한다.
- 바이트 코드는 고급 언어로 작성된 소스 코드를 JVM이 이해할 수 있는 중간 코드로 컴파일한 것을 말한다.
- JVM 로딩
- 클래스 로더를 통하여 바이트 코드를 메모리에 적재한다.
- 이 과정에서 바이트 코드가 런타임 데이터 영역에 적재된다.
- 실행
- 실행 엔진을 통하여 바이트 코드를 실행한다.
- 인터프리터, JIT 두 가지 컴파일러가 존재한다.
그림으로 표현
왜 소스 코드를 바이트 코드로 변환할까?
굳이 왜 소스 코드를 바로 읽어서 실행하면 되지 바이트 코드로 변환하는지 궁금하였다.
검색결과 자바는 "한 번 작성하면 어디서나 실행된다" 라는 목표를 가지고 있다 한다. 이를 위해 자바는 소스 코드를 직접 실행하지 않고 바이트 코드라는 중간 형태로 변환하여 동작을 한다. 이렇게 생성된 바이트 코드를 JVM이 내부 동작을 통해 바이트 코드를 읽고 현재 사용중인 컴퓨터의 기계어로 변환하여 실행된다. 덕분에 자바는 어떤 플랫폼 (특정 하드웨어, 운영체제)에서든 독립적으로 실행할 수 있다. 즉, 플랫폼에 독립적이기 때문에 이러한 방식을 사용하는것 같다.
런타임 데이터 영역
런타임 데이터 영역은 자바 프로그램이 실행 되는 동안 데이터를 저장하고 관리하는 메모리 영역이다. 런타임 데이터 영역은 다음과 같이 구성되어 있다.
- 메서드 영역
- 스택 영역
- 힙 영역
- PC 레지스터
- 네이트 메소드 스택
메서드 영역과, 스택 영역, 힙 영역에 대해서 집중적으로 공부를 하였고 그 외는 간단하게 개념정도만 확인하였다.
메서드 영역
메서드 영역은 JVM의 런타임 데이터 영역 중 하나로, 자바 프로그램 실행 시 클래스와 메서드, 상수 등에 대한 정보를 저장하고 관리하는 메모리 영역이다. 이 영역에 저장된 정보는 JVM 내 모든 스레드에서 공유되며, 프로그램 실행에 필요한 공통 데이터를 관리한다.
주요 역할 및 특징
- 클래스 정보
- 메서드 정보
- 런타임 상수 풀
- 필드 정보
클래스 정보
클래스 로더가 적재한 클래스의 바이트 코드가 메서드 영역에 저장된다. 이 바이트 코드를 통해 JVM이 클래스를 실행할시킬 수 있다. 또한 클래스의 이름, 부모 클래스, 구현된 인터페이스, 접근 제어자 등 클래스의 구조와 관련된 정보가 여기에 모두 저장된다.
메서드 코드
클래스의 모든 메서드에 대한 바이트 코드가 메서드 영역에 저장된다. 자바에서 특정한 클래스를 `new`연산자를 통하여 여러개 생성한다 가정해보자. 그렇게 되면 힙 영역에 여러개의 인스턴스가 생성된다. 하지만 이 클래스의 메서드 코드는 메서드 영역에 한 번만 생성되고 모든 인스턴스는 이 메서드 코드를 공유하여 사용한다.
런타임 상수 풀
런타임 상수 풀은 프로그램 실행 중 필요한 공통 상수들을 보관한다. 예를 들어, "Hello"라는 문자열 상수와 같은 리터럴,또는 메서드 참조와 같은 심볼릭 레퍼런스가 여기에 저장된다. 상수 풀은 클래스가 로드될 때 한 번 실행되며 이우헤는 수정되지 않는다. 자주 사용하는 상수 값을 효율적으로 관리하고 재사용함으로써 성능을 최적화한다.
필드 정보
클래스와 관련된 정적 변수와 상수에 대한 정보를 가지고 있는 영역이다. 프로그램 실행 동안 클래스의 변수와 상수에 접근할 수 있도록한다.
스택 영역
스택 영역은 각 쓰레드가 호출될 때 마다 개별적으로 할당되는 메모리 영역으로, 스택 영역은 메서드 호출과 관련된 정보를 관리한다. 자바에서 자바 프로그램을 실행하게 되면 먼저 main() 메서드가 실행된다. main() 메서드를 실행하면 스택 프레임이 생성되고 또 main() 메서드 내부에서 다른 메서드를 호출하게 되면 프레임이 쌓이는 구조로 동작한다.
스택 프레임은 지역 변수, 중간 연산 결과, 메서드 호출의 반환 주소와 같은 정보를 저장하고 있다. 메서드 호출시 스택 프레임은 생성되고 메서드가 종료되면 스택 프레임을 제거하고 스택 프레임이 모두 제거되면 프로그램도 함께 종료된다.
그렇기 때문에 메서드 내부에서 사용되는 지역 변수는 밖에서 사용할 수 없는것이였다.
힙 영역
힙 영역은 클래스로부터 생성된 인스턴스와 배열을 저장하는 메모리 영역이다. 객체를 만들기 위해 그동안 new 연산자를 사용하여 객체를 생성해왔는데 객체는 바로 힙 영역에 저장되는것였다. 힙 영역은 가비지 컬렉션을 통하여 자동으로 메모리를 관리한다. 가바지 컬렉션은 더 이상 참조되지 않은 객체를 찾아 메모리를 회수하는 역할을 한다.
즉, new 연산자를 활용하여 객체를 생성하게 되면 객체는 힙 영역에 저장되며 생성된 객체의 메모리 주소를 참조하는 참조값을 반환한다. 이 참조값은 변수에 저장되며 객체에 접근하거나 메서드를 호출 할때 사용된다. 또한 변수의 저장된 값이 변경되어 객체를 참조하는 변수가 없다면 자바에서는 가비지 컬렉션을 이용하여 객체를 없애버린다.
정리
자바 가상 머신은 자바 프로그램을 효율적으로 실행하기 위해 만들어졌다. Java 언어로 작성된 프로그램은 먼저 Java 언어로 작성된 소스 파일은 자바 컴파일러가 바이트 코드로 변환한다. 이 변환된 바이트 코드를 JVM의 클래스 로더가 메모리에 에 로드한다. 이 과정에서 바이트 코드는 런타임 데이터 영역에 저장된다. 이제 실행 엔진의 인터프리터와 JIT가 바이트 코드를 읽고 실행한다.
클래스 로더가 메모리에 저장하는 과정에서 런타임 데이터 영역에 바이트 코드가 저장되는데 런타임 데이터 영역은 크게 3가지 영역으로 나눌 수 있다. 바로 메서드 영역, 스택 영역, 힙 영역으로 나눌 수 있는데. 메서드 영역에는 클래스의 정보와 메서드 그리고 공통적으로 사용할 상수, 정적멤버등이 저장되어있으며 클래스를 로드할 때 한 번 실행된다.
그리고 스택 영역에는 지역변수, 중간연산결과, 메서드 호출정보등을 가지고 있으며 메서드를 실행할 때 마다 스택구조로 하나씩 쌓이게 된다. 마지막으로 힙영역에는 클래스로 부터 만들어진 객체와 배열이 저장되며 가비지 컬렉션을 이용하여 메모리 관리를 한다.
결론
나중에 개념을 잊어버려도 작성한 글을 보고 개념을 쉽게 되살릴 수 있게 잘 작성해보자,.
'TIL' 카테고리의 다른 글
[TIL | 2024-09-02] 라이브러리, 프레임워크, 제어의 역전, 스프링 기본 개념 및 특징, 스프링 개발 환경 세팅해보기 (10) | 2024.09.02 |
---|---|
[TIL | 2024-08-30] 웹의 동작 원리와 웹 구성 요소 (0) | 2024.08.30 |
[TIL | 2024-08-28] 예외, 예외 처리 (0) | 2024.08.29 |
[TIL | 2024-08-27] 추상 클래스, 추상 메서드, 인터페이스 (0) | 2024.08.29 |
[TIL | 2024-08-26] 상속, 오버라이딩 (0) | 2024.08.26 |