자바를 이용하는 개발자라면 자바 바이트 코드가 JRE위에서 동작됨을 이해한다.
그러나, JRE에서 가장 중요한 요소는 자바 바이트 코드를 해석하고 실행하는 JVM(Java Virtual Machine)
JVM은 하나의 개념이고, 스펙이다. 이를 구현한 객체가 Java VM, Delvik VM 등이 있다.
JRE는 자바 API와 JVM, Native Method으로 구성되며, JVM의 역할은 자바 애플리케이션을 클래스 로더(Class Loader)를 통해 읽어 들여서 자바 API와 함께 실행하는 것
JVM의 특징
- 스택 기반의 가상 머신
: 대표적인 컴퓨터 아키텍처인 인텔 x86아키텍처, ARM 아키텍처와 같은 하드웨어가 레지스터 기반으로 동작하는 데 비해 JVM은 스택 기반으로 동작한다. - 심볼릭 레퍼런스
: 기본 자료형(primity data type)을 제외한 모든 타입(클래스와 인터페이스)을 명시적인 메모리 주소 기반의 레퍼런스가 아니라 심볼릭 레퍼런스를 통해 참조한다. - 가비지 컬렉션(garbage collection)
: 클래스 인스턴스는 사용자 코드에 의해 명시적으로 생성되고 가비지 컬렉션에 의해 자동으로 파괴된다. - 기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장
: C/C++등의 전통적인 언어는 플랫폼에 따라 int형의 크기가 변한다. JVM은 기본 자료형을 명확하게 정의하여 호환성을 유지하고 플랫폼 독립성을 보장 - 네트워크 바이트 오더(network byte order)
: 자바 클래스 파일은 네트워크 바이트 오더를 사용한다. 인텔 x86아키텍처가 사용하는 리틀 엔디안이나, RISC 계열 아키텍처가 주로 사용하는 빅 엔디안 사이에서 플랫폼 독립성을 유지하려면 고정된 바이트 오더를 유지해야 하므로 네트워크 전송 시에 사용하는 바이트 오더인 네트워크 바이트 오더를 사용한다. 네트워크 바이트 오더는 빅 엔디안이다.
여기서 스택 기반의 가상 머신이 의미하는 바가 무엇이고, 심볼릭 레퍼런스가 의미하는 바가 무엇인지 확인해보자.
1. 레지스터 기반 vs 스택 기반 VM
가상머신의 구현체는 명세서를 어떻게 구현하냐에 따라 여러 종류가 된다고 한다.
일반적으로, 물리적인 CPU에 의해 처리되는 동작을 흉낼 수 있어야 하며, 아래와 같은 컨셉을 가진다고 한다.
[가상 머신이라면 구현해야할 컨셉]
- 소스 코드를 VM이 실행가능한 바이트 코드로 변환한다.
- 명령어와 피연산자를 포함하는 데이터구조를 가지고 있어야 한다.
- 함수를 실행하기 위한 콜 스택
- IP(Instruection Pointer): 다음 실행할 곳을 지정하는 포인터
- 가상 CPU: 다음 명령어를 패치&명령어를 해석&명령을 실행
위와 같은 명세를 만족하는 가상머신을 구현하는 방법으로 2가지.
Stack / Register 기반이 있다.
이 둘의 차이점은 피연산자를 저장하고 다시 가져오는 메카니즘이 다르다.
1.1 Stack 기반 가상머신은
- Java VM,
- 대다수의 가상머신이 스택 기반
- 피연산자와 연산 후 결과를 스택에 저장
- 예를 들어, 아래와 같이 덧셈을 할 경우, 스택구조라서 PUSH & POP이 필요하며 4단계의 명령이 필요하다.
- 장점: 다음 피연산자의 메모리 위치를 기억할 필요가 없다. SP(stack pointer)가 다음 피연산자의 위치를 나타낸다. 즉 스택에서 POP만 하면 다음 피연산자가 나오기 때문에 피연산자의 메모리를 기억할 필요가 없다.
1.2 Register 기반 가상머신
- Lua, Dalvik VM
- 피연산자가 CPU의 레지스터에 저장
- PUSH & POP연산자가 없다.
- 명령어가 피연산자의 위치인 레지스터의 주소를 기억해야 한다.
- 장점
1) 아래와 같이 POP & PUSH 과정이 없기 떄문에 같은 덧셈이라도 하나의 명령으로 충분하다. 때문에 더 빠르다.
2) 스택 기반에서는 할 수 없는 명령어 최적화를 적용할 수 있다. 예를 들어, 어떤 연산이 나중에 또 필요할 때, 레지스터에 저장하여 다시 계산하지 않고도 연산 결과를 활용할 수 있다.
- 단점
스택기반보다 명령어의 길이가 길다. 피연산자의 주소를 명시해줘야 하므로 평균적으로 길 수 밖에 없다.
2. 심볼릭 레퍼런스란 무엇인가?
참고하는 클래스의 특정 메모리 주소를 참조 관계로 구성한 것이 아니라, 참조하는 대상의 이름만을 지칭한 것이다. Class 파일이 JVM에 올라가게 되면 Symbolic Reference는 그 이름에 맞는 객체의 주소를 찾아서 연결하는 작업을 수행한다. 그러므로, 실제 메모리 주소가 아니라 이름만을 가진다.
3. 바이트 오더(byte order)란 무엇인가?
메모리 주소를 부여하는 방식으로, 점점 크게 부여하거나 점점 작게 부여하는 방식을 의미한다. 대표적인 예시로 빅엔디안, 리틀엔디안이라는 것이 있고, 이는 시스템이 내부적으로 데이터를 표현하는 방법을 의미한다.
네트워크 바이트 오더의 의미는 무엇인까?
빅엔디안을 의미하고, 데이터가 상위 바이트부터 메모리에 적재하여, 가상 최상위 바이트(0A)가 가장 낮은 메모리 주소에 저장되는 방식을의미합니다.
[참고자료]
'아키텍쳐를 고민하기' 카테고리의 다른 글
JVM 이해하기 - 3 (JVM 구조 - 클래스로더, 런타임 데이터 영역, 실행 엔진) (0) | 2020.11.25 |
---|---|
JVM 이해하기 - 2 (자바의 바이트 코드) (0) | 2020.11.24 |
안정성:패키지 결합도의 원칙 (0) | 2020.09.05 |
단위 크기:패키지 응집도의 원칙 (0) | 2020.09.05 |
패키지 설계의 원칙 이란 무엇일까? (0) | 2020.09.05 |
댓글