1️⃣ 자바의 메모리 영역과 컴파일

a. 메모리 영역

  1. 클래스 변수: 객체 사이에 공유하는 변수로 클래스 영역에서 static으로 선언 → 클래스가 메모리에 올라갈 때 Method 영역에서 할당된다.
  2. 인스턴스 변수: 객체/인스턴스마다 다른 값 저장하는 변수로 클래스 영역에서 선언 → Heap 영역에서 할당되고 참조 변수가 없는 경우 가비지 컬렉터에 의해 자동 제거됨
  3. 지역변수: 메서드 영역에서 선언되는 변수로 메서드 끝나면 소멸된다.
  4. 매개변수: 메서드 호출시 전달되는 값을 저장하는 변수로 메서드 끝나면 소멸된다.
영역 역할 저장 데이터 공유 여부 생명주기
Method Area 클래스 구조 및 메타데이터 저장 클래스 메타데이터, 메서드 메타데이터, 상수, 정적(static)변수 모든 스레드가 공유 JVM이 종료될 때까지 유지
Heap 객체와 배열 저장 객체, 배열, 객체 내부의 멤버 변수 모든 스레드가 공유 Garbage Collector가 관리
Stack 메서드 호출과 지역 변수 관리 지역 변수, 메서드 호출 정보, 참조 변수 스레드별로 독립 메서드 종료 시 자동 해제

b. 컴파일 과정 순서

  1. 개발자가 자바 소스코드(.java)를 작성한다.
  2. 자바 컴파일러(Java Compiler)가 자바 소스파일을 컴파일한다. 이때 나오는 파일은 자바 바이트 코드(.class)파일로 아직 컴퓨터가 읽을 수 없는 자바 가상 머신이 이해할 수 있는 코드이다.
  3. 컴파일된 바이트 코드를 JVM의 클래스로더(Class Loader)에게 전달한다.
  4. 클래스 로더는 동적로딩(Dynamic Loading)을 통해 필요한 클래스들을 로딩 및 링크하여 런타임 데이터 영역(Runtime Data area), 즉 JVM의 메모리에 올린다.
  5. 실행엔진(Execution Engine)은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행한다. 이때, 실행 엔진은 두가지 방식으로 변경한다.
    1. 인터프리터 : 바이트 코드 명령어를 하나씩 읽어서 해석하고 실행한다. 하나하나의 실행은 빠르나, 전체적인 실행 속도가 느리다는 단점을 가진다.
    2. JIT 컴파일러(Just-In-Time Compiler) : 인터프리터의 단점을 보완하기 위해 도입된 방식으로 바이트 코드 전체를 컴파일하여 바이너리 코드로 변경하고 이후에는 해당 메서드를 더이상 인터프리팅 하지 않고, 바이너리 코드로 직접 실행하는 방식이다. 하나씩 인터프리팅하여 실행하는 것이 아니라 바이트 코드 전체가 컴파일된 바이너리 코드를 실행하는 것이기 때문에 전체적인 실행속도는 인터프리팅 방식보다 빠르다.

2️⃣ 가비지 컬렉션(Garbage Collection)

  1. 정의와 동작 방식
  1. Young 영역(Young Generation)

    1. 새롭게 생성된 객체가 할당(Allocation)되는 영역

    2. 대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.

    3. Young 영역에 대한 가비지 컬렉션(Garbage Collection)을 Minor GC라고 부른다.

    4. Young 영역을3가지 영역(Eden, survivor 0, survivor 1) 으로 나눈다.

    5. Old 영역(Old Generation)

    6. Young영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역

    7. Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.

    8. Old 영역에 대한 가비지 컬렉션(Garbage Collection)을 Major GC 또는 Full GC라고 부른다.

    ⭐️ Yung 영역의 Eden부터 채워지면서 가득차게 되면 GC(Mark)를 통해 참조되지 않는 객체를 제거하고 살아 남은 객체들의 age가 1개 증가허고 survivor 0 또는 survivor 1 로 넘어가게된다. survivor 0 또는 survivor 1로 넘어간 객체들이 Eden이 다시 가득찰때마다 GC의 Mark 검사를 받게 되어 식제 되거나 survivor 0 또는 survivor 1 사이에 age값이 계속 증가하면서 이동하게 된다. 하지만 age값이 임계값을 도달하게 되면 그 객체가 Old 영역에 넘어가게된다.

    → Major GC는 Old 영역은 데이터가 가득 차면 GC를 실행하는 단순한 방식이다. Old 영역에 할당된 메모리가 허용치를 넘게 되면, Old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 Major GC가 실행되게 된다.하지만 Old Generation은 Young Generation에 비해 상대적으로 큰 공간을 가지고 있어, 이 공간에서 메모리 상의 객체 제거에 많은 시간이 걸리게 된다. 예를들어 Young 영역은 일반적으로 Old 영역보다 크키가 작기 때문에 GC가 보통 0.5초에서 1초 사이에 끝난다. 그렇기 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않는다. 하지만 Old 영역의 Major GC는 일반적으로 Minor GC보다 시간이 오래걸리며, 10배 이상의 시간을 사용한다. 바로 여기서 모든 스레드를 멈추고 GC 스레드만 남기는 현상인 Stop-The-World 문제가 발생하게 된다. Major GC가 일어나면 Thread가 멈추고 Mark and Sweep 작업을 해야 해서 CPU에 부하를 주기 때문에 멈추거나 버벅이는 현상이 일어난다.

  2. Python Garbage Collection 동작 원리 (다른 프로그래밍 언어의 GC 비교)

→ Python은 객체의 생성과 소멸 시점을 명확히 알 수 있지만, 순환 참조가 있을 경우 별도의 감지가 필요하다. 성능은 자바보다 낮을 수 있습니다.

  1. Java GC의 여러 종류

  2. Serial GC

    1. Parallel GD
    1. Parallel Old GC
    1. CMS GC
    1. G1 GC
    1. Shenandoah GC
    1. ZGC (Z Garbage Collector)

Q) 그럼 많은 자바 GC 중에서 선택할 때 어떤 것을 고려해야할까?

  1. 실시간 처리(낮은 지연 시간 중요) → ZGC, Shenandoah GC, G1 GC
  2. 대규모 데이터 처리(높은 처리량 중요) → Parallel GC, Parallel Old GC
  3. 소규모 애플리케이션 → Serial GC, G1 GC
  4. 대규모 메모리(4GB 이상) → G1 GC, ZGC
  5. 클라우드 기반의 대규모 서비스 → ZGC, Shenandoah GC
  6. 일반적인 엔터프라이즈 애플리케이션 → G1 GC

3️⃣ JVM관점에 static을 왜 조심해서 써야하는지 서술하시오

4️⃣ 자바의 OOP, 추상화, 캡슐화

  1. OOP (Object Oriented Programming) 자바에서 객체지향 프로그래밍(OOP)은 객체(책임/역할)를 중심으로 설계하고 구현하는 프로그래밍 방법이다. 객체지향프로그래밍의 중요한 특성은으로 크게 캡슐화, 추상화, 다형성, 상속성이 있다. 또한, 자바 OOP에서 유지보수 가능, 확장 가능, 가독성 높이기 위해 SOLID 원칙이라는 5가지 주요 원칙이 있다.

SOLID 원칙 5가지

  1. Single Responsibility Principle (단일 책임 원칙) : 클래스는 단 하나의 책임(역할)만 가져야 한다.
  2. Open/Closed Principle (개방-폐쇄 원칙) : 소프트웨어 요소는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다.
  3. Liskov Substitution Principle (리스코프 치환 원칙) : 상위 클래스의 객체는 하위 클래스의 객체로 대체할 수 있어야 한다.
  4. Interface Segregation Principle (인터페이스 분리 원칙): 특정 클라이언트에 맞는 인터페이스만 제공해야 하며, 사용하지 않는 메서드는 포함하지 말아야 한다.
  5. Dependency Inversion Principle (의존 역전 원칙) : 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화(인터페이스)에 의존해야 한다.

  1. 추상화 (Abstraction) 추상의 사전적인 의미는 "여러가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용"이다. 그러므로 추상화는 여러 개체들을 분해해서 찾을 수 있는 공통되는 특성을 관심 영역에 따라 재조합하는 것이라고 이해할 수 있다.

예를 들어

이러한 행위들은 클래스 안의 메서드로 추상화시킬 수 있다. 마찬가지로 환자(사람)의 다양한 속성 시력, 몸무게, 고객의 직업, 연봉 등도 클래스 안의 속성, 즉 필드로 추상

→ 따라서 추상화는 모델링이며, 클래스는 추상화의 결과라고 말할 수 있다. → 이렇게 추상적으로 끄집어 낸 개념들을 큰 틀에서 클래스로 만든것이 바로 추상클래스이다.