

정의
JVM 은 Java Virtual Machine 자바 가상머신의 약자로 자바 프로그램이 수행되는 프로세스이다. 여기서 프로세스라는 말은 운영 체제에서 실행 중인 프로세스로 볼 수 있으며 자바 가상 머신도 하나의 가상적인 환경에서 동작하는 가상머신 즉 프로세스로 이해할 수 있는 것이다.
JVM은 정확한 정의가 있어 구현된 것이 아닌 표준화된 정의만이 존재하는 스펙이라고 할 수 있는데 JVM 벤더들(Oracle, IBM 등)은 이러한 표준에 맞도록 자신의 JVM을 별도로 구현하여 사용하곤 한다. 즉, JVM은 정의된 스펙을 구현한 프로세스 형태로 구동되는 런타인 인스턴스라고 할 수 있다.
역할
자바 컴파일 - 프로그램의 자바 소스 코드(.java)를 바이트 코드(.class)로 변환하는 과정을 의미한다. 자바 컴파일을 통해 생성된 바이트 코드(.class)는 JVM 이 읽고 자바 바이트 코드(.class)를 실행할 수 있는 환경을 제공한다. 이를 통해 자바는 OS에 상관없이 자바 어플리케이션을 실행할 수 있는 것이다.
JVM 메모리 구조
Garbage Collector - 힙 메모리 영영에 생성된 객체들 중 참조되지 않은 객체 제거
Execution Engine - 런타임 데이터 에리어에 배치된 바이트 코드 실행, .class 파일을 실행한다고 보면 된다.
Class Loader - JVM에 클래스 파일 로드하고 배치, 런타임시에 동적으로 클래스를 로드
------------------- Runtime Data Area 영역 ------------------------------------------------------------------------------------------------------------
Method Area - 모든 쓰레드가 공유하는 메모리 영역이며, Class, Interface, Method, Field, Static 변수 등의 바이트 코드를 보관한다.
Stack - 메소드 호출 시 해당 메소드만을 위한 스택 프레임이 생성되며 호출된 메소드에서 사용되는 값들이 저장된다. 호출된 메소드의 매개변수, 지역변수, 리턴 값, 연산 시 일어나는 값들을 임시로 저장한 후 메소드 수행이 종료되면 프레임이 삭제된다. 스택은 LIFO로 처리된다.
Heap - 모든 쓰레드가 공유, 가비지 컬렉션 관리 영역, new 명령어로 생성된 인스턴스와 객체가 저장되는 구역
PC Register - 현재 수행중인 JVM 명령의 주소값이 저장된다.(각 쓰레드 별로 생성)
Native Method Stack - 자바 외 언어로 작성된 Native 코드를 위한 영역이다.
Garbage Collector 가 왜 좋을까?
c언어에서는 malloc 함수를 활용해서 개발자가 필요한 메모리를 직접 할당받아 사용하고 free 함수를 활용해 사용한 메모리를 반환한다. 그러나 자바에서는 그러한 귀찮은 과정을 Garbage Collector가 힙 영역에서 참조되지 않은 객체들을 자동으로 제거함으로써 메모리의 효율성을 높였다.
객체 생성과정
1. new 키워드를 이용해 객체 생성 시 Class Loader에 의해서 Method Area 에 클래스에 대한 내용이 저장된다.
2. heap 영역에 메모리가 할당되며 객체 정보가 생성된다.
3. 객체 생성자가 호출되고 할당된 객체의 주소가 변수에 할당된다.
Call by value, Call by reference
우리가 A라는 함수를 호출한다고 했을 때 A(매개변수); 라고 호출할 것이다. 이때 매개변수로 원시타입이냐 참조타입이냐에 따라 Call by value, Call by reference가 나눠진다.
1. 원시타입인 경우
원시타입이란 아래와 같은데 원시타입의 특징은 해당 값을 실제로 JVM의 STACK에 저장하는 것이다.
원시타입의 변수를 매개변수로 전달할 경우 해당 A 메소드(수신자)의 파라미터와 호출자의 변수는 별개로 구분된다.
종류 | 데이터형 | 크기 | 범위 |
논리형 | boolean | 1 / 8 | true 또는 false |
문자형 | char | 2 / 16 | '\u0000' ~ 'uFFFF' (16비트 유니코드 문자 데이터) |
정수형 | byte | 1 / 8 | -128 ~ 127 |
정수형 | short | 2 / 16 | -32768 ~ 32767 |
정수형 | int | 4 / 32 | -2147483648 ~ 2147483647( -21억 ~ + 21억) |
정수형 | long | 8 / 64 | -9223372036854775808 ~ 9223372036854775807(-100경 ~ + 100경) |
실수형 | float | 4 / 32 | 1.4E-45 ~ 3.4028235E38 |
실수형 | double | 8 / 64 | 4.9E-324 ~ 1.7976931348623157E308 |
대체 이게 뭔 소리일까? 라고 생각하실 수도 있다.
2. 참조타입인 경우
참조 타입으로는 객체와 배열등이 있는데
원시타입과 다르게 참조타입의 특징은 해당 값을 실제로 저장하는 곳은 JVM의 HEAP이지만 값을 사용할 때는 해당 객체 값의 주소를 STACK에서 참조해서 사용한다는 것이다.
Primitive Type 원시타입과 Reference Type 기본값의 차이
원시타입의 경우 선언을 하는 순간 초기화를 하지 않아도 메모리 공간을 차지하고 있고 int, byte 0으로 boolean은 false이다.
반면에 참조타입의 경우 선언을 하지 않으면 null 이다. null인 객체를 사용할 경우Null Pointer Exception이 발생한다.
public class MyClass {
private String myString;
public static void main(String[] args) {
MyClass myObject = null; // 객체가 아직 생성되지 않았음
// 아래의 코드는 Null Pointer Error를 발생시킬 수 있음
System.out.println(myObject.myString);
}
}
형변환에 있어서 long타입은 64bit인데 32bit인 float 으로 자동형변환이 가능한 이유가 뭘까?
왜냐하면 정수는 10의 지수 형태로 표현이 가능하기 때문이다.
1234 = 1.234 * 10^3 의 형태를 보자 자바에서 데이터 타입의 크기만을 비교해서 형변환이 되는 것이 아니다.
명시적 형변환은 큰 데이터 타입을 작은 데이터 타입에 우겨넣는 것이기 때문에 데이터 유실이 발생할 수 있다.

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!