해당 그림은 자바 7 이하 버전의 전체 구조이다.
자바 7 이하 버전의 메소드 영역
PermGen(Permanent Generation) ↔ 메소드 영역(Method Area)
자바 7 이하 버전에서는 메소드 영역에 해당하는 메모리 공간이 PermGen 영역에 있었다.
클래스 메타데이터(클래스 이름, 메소드, 상수 풀, 클래스 변수 등)를 저장하는 영역
PermGen에 저장되는 정보들
// 클래스 이름 / 부모 클래스 (Object) -> 저장 O
public class Example {
// 클래스 변수 (Static Field) -> 저장 O
public static String CLASS_NAME = "ExampleClass";
// 인스턴스 변수 -> 저장 X
private int instanceVariable;
// 상수 풀 (문자열 리터럴, 상수 값) -> 저장 O
public static final int MAX_VALUE = 100;
// 생성자 -> 저장 O
public Example(int instanceVariable) {
this.instanceVariable = instanceVariable;
}
// static 메소드 (Method) -> 저장 O 정의된 메소드 이름 / 접근 제어자 / 반환 타입
public static void printClassName() {
System.out.println(CLASS_NAME);
}
// instance 메소드 -> 저장 O 메소드는 모두 저장
public int getInstanceVariable() {
return instanceVariable;
}
}
자바 8 이후 버전의 메소드 영역
자바 8부터는 PermGen이 Metaspace로 대체되었고, 이 Metaspace는 OS의 네이티브 메모리를 사용한다.
즉 JVM이 OS로부터 할당 받은 메모리에 있는게 아닌 OS 메모리에서 관리된다.
자동 메모리 관리
Metaspace는 필요에 따라 자동으로 확장한다.
PermGen처럼 고정된 크기를 설정할 필요가 없으며, OS 메모리가 허용하는 범위까지 확장 가능하다.
메모리 오버헤드 감소
고정된 메모리 크기 설정으로 인해 발생하던 PermGen OutOfMemoryError가 줄어든다.
자바 가상 머신(JVM)의 동작 방식
자바 가상 머신인 JVM(Java Virtual Machine)인 JVM의 역할은 자바 애플리케이션을 클래스 로더를 통해 읽어
자바 API와 함께 실행하는 것이다.
간단하게 컴파일된 코드 확인
public class App {
public static void main(String[] args) {
System.out.println("Hello");
}
}
컴파일 (javac)
확인하면 App.class 바이트 코드 파일이 생성된 걸 확인할 수 있다.
javap 명령어로 바이트 코드를 확인
javap 도구는 자바의 역어셈블러로, 컴파일된 바이트 코드 파일을 읽고 사람이 읽을 수 있는 형태로 변한해준다.
JVM, JDK, JRE 개념 설명
https://20240228.tistory.com/317
자바 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당받는다.
자바 컴파일러(javac - from JDK)가 자바 소스코드(.java)를 자바 바이트 코드(.class)로 컴파일
Class Loader는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크 하여 Runtime Data Area(JVM이 실질적인 메모리를
할당 받아 관리하는 영역)에 올린다.
Runtime Data Area에 로딩 된 바이트 코드는 Execution Engine을 통해 해석된다.
이 과정에서 Execution Engine에 의해 Garbage Collector의 동작과 Thread 동기화가 이루어진다.
Class Loarder System
- .class 에서 바이트코드를 읽고 메모리에 저장
- 로딩: 클래스 읽어오는 과정
- 링크: 레퍼런스를 연결하는 과정
- 초기화: static 값들 초기화 및 변수에 할당
자바 가상 머신(JVM)의 구조
JVM 구성
- 클래스 로더 (Class Loader)
- 실행 엔진(Execution Engine)
- 인터프리터(Interpreter)
- JIT 컴파일러(Just in Time)
- 가비지 콜렉터(Garbage Collector)
- 런타임 데이터 영역 (Runtime Data Area)
- 힙 영역
- 스택 영역
- 네이티브 메소드
- PC Register
- 메소드 영역(자바7) → 자바8 (메타 스페이스 - OS 네이티브 메모리)
- JNI - 네이티브 메소드 인터페이스(Native Method Interface)
- 네이티브 메소드 라이브러리(Native Method Library)
클래스 로더 (Class Loader)
클래스 로더는 JVM 내로 클래스 파일(.class)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
즉, 로드된 바이트 코드를 엮어서 JVM 메모리 영역인 Runtime Data Area에 배치한다.
클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고, 애플리케이션에서 필요한 경우 동적으로
메모리에 적재하게 된다.
클래스 파일의 로딩순서
Loading(로딩) → Linking(링크) → Initialization(초기화)
- Loading(로딩): 클래스 파일을 가져와서 JVM의 메모리에 로드한다.
- 클래스 로더가 .class 파일을 읽고 그 내용에 따라 적절한 바이너리 데이터를 만들고 메소드 영역(메타 스페이스)에 저장
- 이때 메소드 영역(메타 스페이스)에 저장하는 데이터
- FQCN (Fully Qualified Class Name): 클래스 전체 이름, 패키지 포함
- 클래스 | 인터페이스 | 열거형(Enum): 클래스 구조와 타입
- 메소드와 변수 정보: 해당 클래스에 정의된 메소드, 변수들의 정보 (이름, 타입, 접근 제어자...)
- 로딩이 끝나면 해당 클래스 타입의 Class 객체를 생성하여 힙 영역에 저장
이 클래스(Class) 객체는 클래스의 메타데이터를 관리하며, 클래스의 인스턴스를 생성하거나 리플렉션(Reflection) 같은 메커니즘을 통해 클래스 정보를 얻을 때 사용된다.
- Linking(링크): 클래스 파일을 사용하기 위해 검증하는 과정이다.
- Verifying(검증): 읽어들인 클래스가 JVM 명세에 명시된 대로 구성되어 있는지 검사
명세에 부합하지 않으면 실행이 실행이 중단된다.
해당 단계는 JVM 보안성을 보장하는 중요한 단계이다. - Preparing(준비): 클래스가 필요한 메모리를 할당, 클래스 변수를 기본값으로 초기화
예를 들어 static 변수가 선언되어 있으면, 이 변수에 메모리 공간을 할당하고 기본값으로 설정한다.
ex) int 0으로 초기화 - Resolving(분석): 클래스의 상수 풀(Constant Pool) 내 모든 심볼릭 래퍼런스를 다이렉트 래퍼런스로 변경
심볼릭 래퍼런스(참조하는 대상의 이름) / 다이렉트 래퍼런스(실제 메모리 주소)
- Verifying(검증): 읽어들인 클래스가 JVM 명세에 명시된 대로 구성되어 있는지 검사
- Initialization(초기화): static 변수 / static 블록들을 적절한 값으로 초기화한다. (static 필드들을 설정된 값/ 기본값 으로 초기화)
static 블록이 있으면 실행한다.
★
로딩 시점에 만들어진 Class 객체
public class App {
public static void main(String[] args) {
Class<App> appClass1 = App.class; // 로딩 시점에 만들어진 Class<App> 객체 -> 힙 영역에 저장
App app = new App();
Class<? extends App> appClass2 = app.getClass();
}
}
★
보면 Linking 단계의 Preparing과 Initialization 단계에서 모두 static 변수의 초기화가 이루어지는데, 두 단계에서 수행하는 초기화의 의미가 다르다.
Linking의 Preparing 단계에서의 static 변수 초기화
이 단계에서는 기본값으로 초기화가 이루어진다.
ex) int: 0 boolean: false 참조 타입: null
public static int count = 10; // 'count'는 Preparing에서 0으로 초기화
Initialization 단계에서의 static 변수 초기화
이 단계에서는 실제 값으로 초기화가 이루어진다.
public static int count = 10; // Initialization 단계에서 10으로 설정
★
심볼릭 래퍼런스? / 다이랙트 래퍼런스?
public class Example{
public static final String TEST = "TEST"; // 상수
}
심볼릭 래퍼런스 (Symbolic Reference)
코드에서 Example.TEST 처럼 우리가 변수나 메소드를 참조할 때 이름으로 참조하는 방식이다.
컴파일된 바이트코드에 이런 참조는 이름을 기반으로 기록된다.
즉, 어떤 클래스의 어떤 필드를 참조한다는 식의 정보만 가지고 있다.
다이렉트 래퍼런스 (Direct Reference)
실행 시점에서 해당 참조가 실제 메모리 주소로 변환된 형태이다.
런타임에 JVM은 이 심볼릭 래퍼런스를 실제로 메모리 상의 위치(주소)로 변환해줘야 하며, 이 과정은
Linking - Resolving 단계에서 일어난다.
클래스 로더의 계층 구조 로딩 방식
클래스 로더는 계층 구조로 이뤄져 있으며 기본적으로 세 가지 주요 클래스 로더가 제공된다.
- 부트스트랩(Bootstrap) 클래스 로더: JVM 자체에 내장된 기본 클래스 로더로, 핵심 Java 클래스들을 로드한다.
JAVA_HOME/lib에 있는 코어 자바 API 제공
최상위 우선순위를 가지는 클래스 로더이다. - 확장(Extension) 클래스 로더: ext 디렉토리의 확장 라이브러리를 로드한다.
JAVA_HOME/lib/ext 폴더 또는 java.ext.dirs 시스템 변수에 해당하는 위치에 있는 클래스를 읽는다. - 애플리케이션(Application) 클래스 로더: 애플리케이션의 클래스 패스를 통해 사용자가 정의한 클래스들을 로드한다.
애플레키이션 클래스 패스(애플리케이션 실행할 때 주는 -classpath 옵션 또는 java.class.path 환경 변수의 값에 해당하는 위치)에서 클래스를 읽는다.
이러한 계층 구조(부모-자식 관계)는 클래스 로더가 상위 로더부터 순차적으로 클래스 로딩을 시도하는 방식이다.
public class App {
public static void main(String[] args) {
ClassLoader classLoader = App.class.getClassLoader();
// -> ApplicationClassLoader (사용자 정의) -> AppClassLoader
System.out.println(classLoader);
// -> ExtensionClassLoader -> PlatformClassLoader
System.out.println(classLoader.getParent());
// -> BootstrapClassLoader -> null Native 코드로 구현
System.out.println(classLoader.getParent().getParent());
}
}
// 출력
jdk.internal.loader.ClassLoaders$AppClassLoader@2b193f2d
jdk.internal.loader.ClassLoaders$PlatformClassLoader@6ce253f1
null
Bootstrap 클래스 로더는 네이티브 코드로 구현되어 있어서 자바 코드로 직접 참조가 불가능하다.
그래서 null값을 반환한다.
만약 클래스 로더가 전부 해당 클래스를 읽지 못하면 ClassNotFoundException이 발생한다.
이 예외는 JVM이 요청된 클래스를 찾을 수 없을 때 발생하며, 일반적으로 클래스의 이름이 잘못되었거나 클래스 패스에 해당 클래스가 없을 때 발생한다.
실행 엔진 (Execution Engine)
실행 엔진은 클래스 로더를 통해서 란타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다
자바 바이트 코드는(.class)는 기계가 바로 수행할 수 있는 언어가 아닌 JVM이 이해할 수 있는 중간 레벨로 컴파일 된 코드이다. 그래서 실행 엔진은 이와 같은 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경해준다.
이 수행 과정에서 실행 엔진은 인터프리터와 JIT 컴파일러 두 가지 방식을 혼합하여 바이트 코드를 실행한다.
인터프리터(Interpreter)
인터프리터는 명령어 단위로 하나씩 바이트 코드를 읽고, 그 명령어를 즉시 기계가 이해할 수 있는 코드로 변환하여 실행한다.
이 방식은 빠르게 시작할 수 있는 장점이 있지만, 반복 실행되는 코드에서 매번 명령어를 해석하는 작업이 필요하므로 성능이 떨어질 수 있다.
JIT 컴파일러(Just-In-Time Compiler)
JIT 컴파일러는 자주 실행되는 바이트 코드(핫스팟이라고 부름)를 기계어로 변환하여 캐싱해두고, 이후에는 이 변환된 기계어를 직접 실행한다.
이 과정에서 코드가 반복적으로 실행되는 경우에는 성능을 향상시킬 수 있다.
단, JIT 컴파일러가 동작할 때는 컴파일 시간이 추가적으로 소요되기 때문에, 처음 실행될 때는 인터프리터보다 느릴 수 있지만, 이후 반복되는 코드에 대해서는 성능을 극대화할 수 있다.
JVM 성능 최적화
인터프리터는 초기 구동 시간을 줄여주고, JIT 컴파일러는 성능을 최적화하는 역할을 한다.
이 두가지 방식이 혼합되어 사용됨으로써 JVM은 짧은 응답 시간을 유지하면서도 장기 실행 중인 애플리케이션에서 성능을 극대화할 수 있다.
따라서 클래스 로더가 .class 파일을 읽어 메모리에 로드한 후, JVM은 초기에는 인터프리터를 사용하여 바이트코드를 실행하고, 코드가 자주 사용되면 JIT 컴파일러가 성능을 최적화하여 네이티브 코드로 변환하는 과정을 거친다.
가비지 컬렉터 (Garbage Collector / GC)
JVM은 가비지 컬렉터를 이용하여 Heap 메모리 영역에서 더는 사용하지 않는 메모리를 자동으로 회수해 준다.
C언어는 직접 개발자가 메모리를 해제 해줘야 하지만 JAVA는 GC를 통해서 자동으로 메모리를 실시간 최적화 해준다.
따라서 개발자가 따로 메모리 관리를 하지 않아도 되므로, 더욱 손쉽게 프로그래밍을 할 수 있도록 해준다.
일반적으로 자동으로 실행되지만, 단 GC(가비지 컬렉터)가 실행되는 시간은 정해져 있지 않다.
GC의 동작 방식은 JVM 런타임 데이터 영역에서 설명 하겠다.
JVM Memory(Runtime Data Area)
Runtime Data Area는 JVM 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.
해당 그림은 JAVA 버전 8 이전의 JVM MEMORY 이다.
Method Area(Metaspace - OS 네이티브 메모리), Heap Area 는 모든 쓰레드(Thread)가 공유하는 영역이고, 나머지 Stack Area, PC Register, Native Method Stack 은 각 쓰레드 마다 생성되는 개별 영역이다.
힙 영역 (Heap Area)
힙 영역은 메소드 영역(Metaspace)과 같이 모든 쓰레드가 공유한다.
JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역이다.
힙의 객체는 스택(스택 프레임)의 참조 타입 변수와 연결되어 있다.
즉, 힙의 참조 주소는 스택이 갖고 있고 해당 주소를 통해서만 힙 영역에 있는 인스턴스를 핸들링할 수 있는 것이다.
만일 참조하는 변수나 필드가 없다면 의미 없는 객체가 되기 때문에 이것을 쓰레기로 취급하고 JVM은 쓰레기 수집기인 Garbage Collector를 실행시켜 쓰레기 객체를 힙 영역에서 자동으로 제거한다.
public class Example {
public static void main(String[] args) {
// 1. 객체 생성
MyObject obj1 = new MyObject("첫 번째 객체");
// 2. obj1에 대한 참조를 잃음
obj1 = null; // 이제 obj1이 가리키던 객체는 참조되지 않음
}
}
해당 그림은 Oracle JVM Memory 이다.
벤더 마다 JVM Memory 영역 구현은 살짝 다를 수 있다.
Heap 영역에는 이렇게 4가지 영역이 있다.
(Eden, Survivor1, Survivor2, Old)
해당 그림의 Permanent는 잘못된 영역이다.
해당 그림은 generation 표현을 위해 만들어진 다이어그램
Permanent Generation은 JVM Heap 메모리에 포함이 아닌 특수하고 독립된 영역이다.
https://stackoverflow.com/questions/41358895/permgen-is-part-of-heap-or-not
이 4가지 영역은 다시 물리적으로 Young Generation / Old Generation 영역으로 구분된다.
Young Generation → 생명 주기가 짧은 객체를 GC 대상으로 하는 영역
- Eden: new를 통해 새로 생성된 객체가 위치, 정기적인 쓰레기 수집 후 살아남은 객체들은 Survivor로 이동
- Survivor 0 / Survivor 1 : 각 영역이 채워지게 되면, 살아남은 객체는 비워진 Survivor로 순차적으로 이동
Old Generation → 생명 주기가 긴 객체를 GC 대상으로 하는 영역. Young Generation에서 마지막까지 살아남은 객체가 이동
PermGen
클래스 메타데이터, 정적 변수, 상수 풀, 메서드 정보 등을 저장하던 공간
PermGen은 JVM 메모리 영역중 하나이고 PermGen 영역은 메소드 영역을 포함한다.
해당 영역은 JVM Heap 영역과는 다른 별도의 영역이다.
사실 PermGen과 메소드 영역이 같은 개념 같기도 하다...
PermGen은 JVM 메모리의 실제 구현 부분 메소드 영역은 정의된 논리적 영역
자바 8 이후에는 PermGen 영역이 Metaspace(OS Native Memory)로 대체되었다.
스택 영역 (Stack Area)
스택 영역(Stack Area)은 메서드 호출 시에 생성되는 지역 변수와 호출된 메서드에 대한 정보를 저장하는 역할을 한다.
지역 변수 저장
메서드가 호출될 때, 해당 메서드의 지역 변수(매개변수 포함)는 스택 영역에 저장된다.
각 메서드 호출이 끝나면 해당 지역 변수는 더 이상 접근할 수 없게 되고, 그 메모리는 해제된다.
메서드 호출 및 반환 정보
각 메서드 호출 시 스택 프레임(Stack Frame)이 생성되며, 이 프레임에는 메서드에 대한 정보를 포함한다.
스택 프레임에는 매개변수, 지역 변수, 메서드 반환 주소(어디서 돌아갈지를 알기 위해 필요) 등이 저장된다.
LIFO 구조
스택은 Last In, First Out(후입선출) 구조로 되어 있다.
즉, 가장 나중에 들어온 데이터가 가장 먼저 나간다.
이는 메서드가 호출될 때 스택에 쌓이고, 메서드가 반환될 때 스택에서 제거되는 방식으로 작동한다.
독립성
스택 영역은 각 스레드마다 하나씩 존재하며, 스레드가 시작될 때 할당된다.
쓰레드를 종료하면 런타임 스택도 사라진다.
사이즈 고정
프로세스가 메모리에 로드될 때 스택 사이즈가 고정되어 있어, 런타임 시에 스택 사이즈를 바꿀 수는 없다.
StackOverFlowError
만일 고정된 크기의 JVM 스택에서 프로그램 실행 중 메모리 크기가 충분하지 않다면 StackOverFlowError가 발생하게 된다.
보통 종료 조건이 잘못 주어진 재귀 함수에서 발생한다.
PC 레지스터(Program Counter Register)
PC 레지스터(Program Counter Register)는 CPU 내부에서 중요한 역할을 하는 레지스터로, 현재 실행 중인 명령어의 주소를 저장한다.
Java Virtual Machine(JVM)에서도 PC 레지스터는 유사한 개념으로 사용된다.
현재 명령어 주소 저장
PC 레지스터는 CPU가 현재 실행하고 있는 명령어의 메모리 주소를 저장한다.
명령어가 실행될 때마다 PC 레지스터의 값이 증가하여 다음에 실행될 명령어의 주소를 가리키게 된다.
프로그램 흐름 제어
PC 레지스터는 분기 명령어(예: 조건문, 루프 등)에 의해 변경될 수 있다.
이러한 명령어가 실행될 때 PC 레지스터의 값이 수정되어 프로그램의 흐름이 제어된다
예를 들어, 조건에 따라 다른 코드 블록으로 점프할 때 PC 레지스터의 값이 변경
스레드와의 관계
각 스레드는 고유한 PC 레지스터를 가진다.
이는 여러 스레드가 동시에 실행될 때 각 스레드가 자신이 현재 어떤 명령어를 실행하고 있는지를 추적할 수 있게 해준다.
JVM에서의 PC 레지스터
JVM은 각 스레드마다 별도의 PC 레지스터를 유지하여 각 스레드가 독립적으로 명령어를 실행할 수 있도록 한다.
JVM에서 PC 레지스터는 현재 실행 중인 바이트 코드의 주소를 가리키며, 이 주소를 통해 JVM은 어떤 명령어가 다음에 실행될지 결정한다.
네이티브 메서드 스택 (Native Method Stack)
네이티브 메서드 스택는 자바 코드가 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역이다.
또한 자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행하기 위한 공간이기도 하다.
사용되는 메모리 영역으로는 일반적인 C 스택을 사용한다.
JIT 컴파일러에 의해 변환된 Native Code 역시 여기에서 실행이 된다고 보면 된다.
일반적으로 메소드를 실행하는 경우 JVM 스택에 쌓이다가 해당 메소드 내부에 네이티브 방식을 사용하는 메소드가 있다면 해당 메소드는 네이티브 스택에 쌓인다.
그리고 네이티브 메소드가 수행이 끝나면 다시 자바 스택으로 돌아와 다시 작업을 수행한다.
그래서 네이티브 코드로 되어 있는 함수의 호출을 자바 프로그램 내에서도 직접 수행할 수 있고 그 결과를 받아올 수도 있는 것이다.
네이티브 메소드 스택은 네이티브 메소드 인터페이스(JNI)와 연결되어 있다.
JNI가 사용되면 네이티브 메서드 스택에 바이트 코드로 전환되어 저장되게 된다.
public class App {
public static void main(String[] args) {
// native method -> currentThread()
System.out.println(Thread.currentThread().getName());
}
}
public class Thread implements Runnable {
@IntrinsicCandidate
public static native Thread currentThread();
// 생략 ...
}
currentThread() 구현은 c/c++로 구현 자바로 구현 x
currentThread() 메소드는 네이티브 메소드 라이브러리에 존재하고 JVM은 네이티브 메소드 인터페이스(JNI)를 통해 상호작용한다.
또한 해당 메소드를 사용하면 stack에 쌓이는게 아닌 네이티브 메소드 스택에 쌓인다.
해당 메소드의 반환값은 스택으로 전달 스택에서는 반환값을 사용할 수 있다.
JNI (Java Native Interface)
자바에서 네이티브 메서드(즉, C/C++로 작성된 코드)와 상호 작용할 수 있도록 하는 인터페이스이다.
이를 통해 자바 애플리케이션이 운영 체제의 기본 기능이나 성능이 중요한 작업을 수행할 수 있도록 한다.
Native Method Library
자바 프로그램이 네이티브 코드(플랫폼에 종속적인 언어로 작성된 코드, 예: C/C++)와 상호작용할 수 있도록 지원하는 라이브러리이다.
자바 프로그램이 JVM 내에서 동작하는 것이 일반적이지만, 가끔 JVM이 제공하지 않는 OS 레벨의 기능이나 특정 하드웨어 접근 등을 위해 네이티브 코드와 통신할 필요가 있을 때 사용(시스템 콜)
자바에서는 JNI(Java Native Interface)를 통해 네이티브 메서드와 상호작용을 수행할 수 있다.
이를 통해 자바 코드에서 C/C++로 작성된 네이티브 라이브러리 함수를 호출하거나, 네이티브 코드에서 자바 함수를 호출하는 것이 가능하다.
네이티브 코드 호출
자바 애플리케이션에서 JNI를 사용해 C/C++로 작성된 네이티브 함수를 호출하여 자바에서 할 수 없는 OS 종속 기능이나 성능 최적화가 필요한 작업을 수행한다.
시스템 리소스 접근
자바는 기본적으로 하드웨어나 운영체제 자원에 직접 접근하는 것을 허용하지 않고, 이를 통해 플랫폼 독립성과 메모리 안전성을 보장한다.
대신, 자바에서는 네이티브 메서드를 사용하여 C/C++와 같은 다른 언어로 작성된 코드를 통해 시스템 리소스에 접근할 수 있다.
유저 레벨 직접 접근 금지 - 시스템 콜
자바 애플리케이션은 JVM을 통해 실행되며, JVM은 운영체제의 자원에 직접 접근하지 않는다.
대신, JVM이 관리하는 가상 머신 환경 내에서 메모리 및 CPU와 같은 자원에 접근한다.
이로 인해 애플리케이션이 서로 영향을 미치지 않도록 보호한다.
네이티브 메서드를 사용할 때, 자바 코드가 네이티브 라이브러리의 기능을 호출하게 되면, 이 라이브러리 내에서 운영체제의 시스템 콜을 통해 필요한 자원에 접근한다. 즉, 네이티브 코드가 직접적으로 하드웨어 자원에 접근하는 것이 아니라, 시스템 콜을 통해 운영체제가 제공하는 기능을 활용하는 방식이다.
성능 최적화
특정 성능이 중요한 경우(예: 그래픽 처리, 수학 연산 등)에는 네이티브 메서드를 통해 더 빠르게 처리할 수 있는 C/C++ 코드로 작성하여 성능을 높이는 방식으로 활용한다.
참고 자료
인프런 백기선님 더 자바, 코드를 조작하는 다양한 방법
참고
'Computer Sience > Java' 카테고리의 다른 글
[JAVA] Reflection (0) | 2024.10.10 |
---|---|
[JAVA] 바이트 코드 조작 (2) | 2024.10.10 |
[JAVA] 자바, JVM, JDK, JRE (0) | 2024.10.08 |
[JAVA8] 애노테이션의 변화 (0) | 2024.10.07 |
[JAVA] Annotation (0) | 2024.10.07 |