-
JavaBackEnd/Java 2025. 2. 14. 17:43
Java
특징
- 객체 지향 프로그래밍 (OOP) : Java는 클래스와 객체를 기반으로 하며, 상속, 다형성 같은 OOP 개념을 지원해 코드 재사용과 유지보수가 쉬움
- 플랫폼 독립성 : Bytecode로 컴파일되어 JVM (Java Virtual Machine) 위에서 실행되기 때문에, 운영체제와 상관없이 동일한 코드를 실행
- Garbage Collection : 자동 메모리 관리 (개발자가 직접 메모리 관리할 필요 없이 Garbage Collector 가 필요 없는 객체를 자동으로 메모리에서 제거해줌)
- 멀티스레드 지원 : 멀티스레드 프로그래밍 지원으로 동시에 여러 작업 수행
- 예외처리 : 예외처리를 명시적으로 강제하여 안정적인 코드 작성을 유도 (try catch finally)
- 보안성 : 강력한 보안 모델을 제공하여, 네트워크와 애플리케이션의 보안 위협을 줄임 (Class Loader, Bytecode Verifier, Sandbox Model)
- Library (API 지원) : 표준라이브러리 제공으로 입출력, 네트워킹, DB 연결, 그래픽 인터페이스 구성 등 다양한 기능을 쉽게 구현
- Dynamic Class Loading : 실행 중에도 새로운 클래스나 객체를 동적으로 로드할 수 있어 유연한 프로그램 구성이 가능
JRE / JDK
Java Runtime Environment (JRE)
- Java Application 실행을 위한 환경
- Java Virtual Machine (JVM) : Java 바이트 코드를 실행하는 가상머신
- Class Library: Java 표준 라이브러리 (ex. java.util, java.io etc)
Java Development Kit (JDK)
- Java Application 개발하고 컴파일하는 데 필요한 도구
- JRE(JVM, 표준라이브러리) + Compiler(javac) + Develop Tool
- Develop, Compile, Debug, Excution 위한 환경 제공 (실행, 빌드, 개발)
JVM (Java Virtual Machine)
동작과정
Source Code Compilation -> Class Loading -> ByteCode Excution -> Memory Management1. Class Loader : 바이트 코드 실행
- 필요한 클래스 파일을 메모리에 Load -> Link -> Initilization 수행
- Java Application 실행시, JVM 이 .class 파일을 메모리에 로드하고 동적으로 필요한 클래스를 로드
- Java 코드가 한번 컴파일 되어 바이트 코드로 변환되면, JVM이 설치된 모든 환경에서 동일하게 실행 (플랫폼 독립성 보장)
소스파일 (.java) -> Javac 컴파일러 (명령어) -> 바이트코드 파일 (.class) -> JVM Excution Engine (Window, Mac ..)
2. Execution Engine
- 운영체제에서 이해하는 기계어로 변역
- JVM이 바이트 코드 (기계어)를 해석하고 실행
- Compiler : 초기에 전체코드를 컴파일하여 바이트코드로 전환 (초기 오래걸림, 오류도 한번에 확인)
- Interpreter : 바이트코드 한 줄씩 해석하며 실행 (실행속도 느림, 실행하고 오류확인)
- Just In Time Compiler (JIT) : 자주 사용되는 코드를 기계어로 컴파일하여 성능을 높임 (변환된 기계어는 캐시에 저장되어, 후에 Interpreter를 거치지 않고 빠르게 실행)
3. Runtime Data Area
Memory Structure (메모리 영역을 나누어 관리)
- Heap : 객체를 저장하는 영역, Garbage Collector가 메모리 관리를 수행
- Stack : 메서드 호출 시 생성되는 지역변수, 매개변수, 호출 프레임 등을 저장.
- Method Area : 클래스 메타데이터, 정적 변수, 상수 등 저장
- Program Counter Resgister : 현재 실행 중인 명령어의 주소를 저장
- Native Method Stack : Native Code (C, C++ 등) 에서의 메서드 호출을 관리
Stack (지역변수 및 함수 반환 주소 저장, 반복된 함수 호출을 관리)
- Last In, First Out (LIFO) : 후입선출 방식으로 메모리 관리 (가장 최근에 호출된 함수가 먼저 종료)
- 메모리관리 : 함수 호출 시, 지역 변수나 함수의 호출 정보를 저장하며, 함수 종료 시 메모리에 자동으로 제거
- 속도 : 메모리 할당 및 해제가 빠름, 함수 호출 시 스택 포인터를 이동시키기만 하면 되므로
- 크기제한 : 고정크기, 초과시 stack overflow (큰 데이터 저장에 여려움)
- 용도 : 함수 호출 시 지역변수 및 함수 반환 주소를 저장, 재귀 함수에서 반복된 함수 호출을 관리 (함수 호출 반환에 최적화)
Heap (객체의 인스턴스와 관련된 데이터를 저장, 각 객체마다 메모리 할당)
- 동적 메모리 할당 : 런타임에 동적으로 메모리를 할당하고 해제, 사용자 필요에 따라 메모리 할당
- 메모리관리 : GC 가 담당
- 속도 : 메모리 할당 및 해제가 상대적으로 느림, 동적으로 관리하므로 성능 저하가 있을 수 있음
- 크기 : Stack 보다 크기가 크고, 프로그램 종료까지 유지
- 용도 : 객체 생성 (new 키워드로 메모리 할당), 동적배열, 데이터 구조 변경시
Method Area (클래스 자체에 대한 정보를 저장)
- Class Metadata : 클래스 정의에 대한 정보 (이름, 메서드목록, 필드목록, 클래스 상속정보, 인터페이스 정보 등)
- Static : 정적변수로 선언되어 메소드 영역에 저장 (keyword : static)
- Class 의 모든 인스턴스가 해당 변수를 공유
- Class 로딩 시에 메모리에 할당되며, 프로그램 종료 시까지 메모리에 남음
- Constant Pool : String Literal, Integer Literal, Class Reference 같은 상수 값을 저장하는 공단 (keyword : final)
Instance (keyword : new)
- Class 를 기반으로 메모리에 할당된 실제 객체 (객체의 생성 과정)
- 각 독립적인 객체로 여러 Instance를 생성 할 수 있음
4. Garbage Collector(GC)
- 자동 메모리 관리 : 더 이상 필요하지 않는 객체를 자동으로 메모리에서 제거
- Heap 메모리 정리 : Heap 영역에 할당된 객체 중 참조되지 않는 객체를 탐지하고 삭제하여 메모리 공간 확보
객체생성 -> 객체 참조 확인 -> 객체 수집 및 삭제
GC Algorithm
Mark and Sweep
Mark 단계: 사용 중인 객체를 식별하여 "마크"한다.
Sweep 단계: 마크되지 않은 객체를 메모리에서 삭제한다.
간단하지만 메모리가 단편화될 수 있는 단점이 있다.Copying
- 메모리를 두 영역으로 나누고, 사용 중인 객체만 다른 영역으로 복사하여 메모리를 정리한다.
- 메모리 단편화를 방지할 수 있지만, 메모리 사용량이 많아질 수 있다.
Generational GC
- 자바의 대표적인 GC 방식으로, 객체의 수명을 기반으로 메모리를 관리한다.
- Young Generation: 새로 생성된 객체가 할당되는 공간.
- Old Generation: Young Generation에서 오래 살아남은 객체가 이동하는 공간.
- Young Generation에서 GC가 더 자주 발생하고, Old Generation에서 GC가 덜 발생한다.
- 자주 사용되는 GC 알고리즘: Minor GC(Young 영역), Major GC(Old 영역)
Types
Serial GC
- 단일 스레드를 사용하여 GC를 수행.
- 소규모 애플리케이션에서 적합.
Parallel GC
- 여러 스레드를 사용하여 GC를 병렬로 처리.
- 대규모 애플리케이션에 적합.
CMS (Concurrent Mark-Sweep) GC
- 애플리케이션 실행을 중단하지 않고 동시에 GC를 수행하려고 노력.
- 낮은 지연 시간이 중요한 환경에서 사용.
G1 (Garbage-First) GC
- 메모리를 여러 영역으로 나누고, 가장 많은 가비지가 있는 영역부터 수집.
- 큰 힙과 낮은 지연 시간이 필요한 환경에서 자주 사용.
4. Java Native Interface (JNI)
- Java가 Native Code 와 상호 작용할 수 있도록 돕는 인터페이스
- 성능향상 : 복잡한 계산이나 시스템 호출을 C, C++와 같은 네이티브 언어로 구현
- 기존 네이티브 라이브러리 사용 : 이미 작성된 C/C++ 라이브러리나 운영 체제 API를 재사용
- 하드웨어나 OS의 직접 접근 : Java만으로는 불가능한 하드웨어나 시스템 자원에 대한 직접적인 접근