Java week1


1주차

JVM이란 무엇인가
컴파일 하는 방법
실행하는 방법
바이트코드란 무엇인가
JIT 컴파일러란 무엇이며 어떻게 동작하는지
JVM 구성 요소
JDK와 JRE의 차이

JVM이란 무엇인가

  • Java Virtual Machine

  • 읽어보기: 모든 프로그램 및 프로그래밍 코드는 CPU에서 동작한다. C 계열(native code)은 CPU에서 바로 동작이 가능하다. 반면 특히 Java 언어 혹은 JVM 언어라 불리우는 코드들은 byte code로 구성되어 실행시킬 가상 머신이 필요한데 즉 JVM이라고 불린다. 이 말은 C 계열의 native code 들은 cpu와 OS에 종속적이다. 프로그램이 컴파일되면서 실행되는 환경(플랫폼)에 종속적이게 된다. JVM 언어들은 JVM위에서 동작하기 때문에 플랫폼에 종속적이지 않다. 이 말은 OS에 맞게 해석 해주는 역할 을 담당하기 때문이다. JVM은 OS에 종속적이지만 동일한 실행 결과를 보장한다. JVM이라는 녀석이 중간에 끼어있다보니 느리다는 인식이자 사실이 있다.

  • 역할: Javac(Compiler)가 프로그래머가 작성한 .java 파일을 byte code인 .class 파일로 변환해주고, byte code를 OS에 상관없이 해석하여 실행하도록 해준다.

  • 설치: JDK와 JRE를 설치하면 자동으로 설치된다.

    • JDK와 JRE는 하단에서 다시 설명

컴파일 하는 방법

  • CLI
    • ➜ javac *.java

실행하는 방법

  • 확장자 .class를 제외하고 아래와 같이 실행
    • ➜ java HelloWorld

바이트코드란 무엇인가

  • 바이트 코드: 플랫폼에 종속적이지 않는 이진코드로 cpu가 이해하는 것이 아니라 JVM 같은 가상 머신이 이해가능한 코드 ex) 자바 바이트 코드
    • 바이트 코드는 ClassLoader에 의해서 JVM의 Runtime Data Area 에 올라가게 됨
  • 바이너리 코드: 기계어 0과 1로 이루어진 이진코드

JIT 컴파일러란 무엇이며 어떻게 동작하는지

  • 읽어보기: 기계어로 빠르게 변환해주는 JVM 내부의 최적화된 컴파일러. Run Time 중에 JVM에서 돌아가는 자바 바이트 코드를 플랫폼에 맞는 네이티브 코드(기계어)로 컴파일 해준다. 즉 자바 바이트 코드 -> 기계어로 컴파일 하는 시간이 있는 만큼 느리다는 생각이 있지만, JIT 컴파일러는 JRE의 일부로서 바이트 코드를 컴파일하는 과정에서 최적화하여 속도를 향상 시켜준다.

  • 동작방식: JIT Compiler는 유사한 바이트코드를 매번 다시 컴파일하지 않고, 캐싱해둬서 컴파일에 필요한 총 시간을 단축한다. 참고: https://lazymankook.tistory.com/79

JVM 구성 요소

  • Class Loader: JVM Run Time Area에 *.java를 런타임에 로딩한다.
  • Execution Engine: *.java 를 기계어(네이티브 코드)로 변환하여 실행한다. Interpreter 즉 명령을 순차로 읽으면서 실행한다. main 함수를 포함해야 한다.
  • Garbage Collector: 동적으로 할당한 Heap 메모리 영역에서 사용하지 않은 (참고되지 않는) 메모리를 해제하는 기능. 즉 Stack 영역을 스캔하여 Heap에서 참조되지 않는 객체를 Heap에서 날림
    • Mark(사용하는 객체가 있는지 탐색하고 체크) & Sweep (삭제)를 하게 된다.
  • 메모리 구조
    • Method: Class Loader 가 적재한 클래스 정보(인퍼테이스 포함), Static 변수(기본형이 아닌 변수의 인스턴스는 Heap에 저장), JVM이 시작할 때 올라가는 정보들을 가지고 있는다. 모든 Thread 가 공유한다.
    • Stack: Thread마다 동적으로 생성된 영역. ex) 객체의 주소=참조변수 Person P = new Person(“aaa”), Primitive Type
    • PC Register: Thread가 어떤 부분을 어떤 명령어로 수행할 지. 즉 실행하는 주소를 저장한다. cf. cpu register counter: 다음에 실행될 주소를 저장
    • Native Method Stack: Java 이외의 언어로 작성된 네이티브 코드가 올라가는 메모리 영역
    • Heap: 구조는 이미지를 참조. new 연산자로 생성된 객체를 저장.
      • eden: 새로 생성되는 객체
      • servival0~1: eden 영역이 가득차고 young(minor) GC가 반복되어 살아남은 객체
      • old generation: young generation의 servival0~1에서 특정 조건(age)이 충족된 객체가 상주

GC 참고

  • 동작
새로 생성(new 연산자)되는 객체가 eden에 상주 -> eden full 되면
mark & sweep 과정으로 servical0 에 옮겨지며, servival 0이 가득차면 1로 1이 가득차면 0으로 이동하며 상주하게 되며 age가 증가한다.
(young generation 영역에서 발생하는 gc를 youn(minor) gc라고 한다.)
이 때, servival x 에서 일정 age 이상인 경우에 old generation 옮겨지는데 old generation 영역이 가득차게되면 old(major) GC가 발생한다.
  • 종류
    1. serial GC: GC용 쓰레드 1개, 싱글 CPU에서 사용 -> Stop the world 결국 발생
    2. Parallel GC: Java 8의 Default GC. GC용 쓰레드가 따로 존재 -> Stop the world 결국 발생
    3. CMS GC: Concurrent Mark Sweep. GC용 쓰레드가 계속 백그라운드에서 작업. 멈추지 않는 장점. cpu 부하. 중간중간 메모리를 제거하므로 파편화 -> 압축기능 없음
    4. G1 GC: 메모리를 기존처럼 연속된 사이즈로 나누지 않고, Region 단위로 구분하여 탐색하고 정리 ex) eden 영역 여러개 -> Region을 정리할 때 참조되는 객체는 다른 Region으로 옮김

JDK와 JRE의 차이

  • JRE(Java Runtime Environment)
    • 이미 개발된 프로그램을 실행하고자 할 때 필요한 자바 실행 환경
    • JVM + 표준 클래스 라이브러리
  • JDK(Java Development Kit)
    • Java SE(Standard Edition)의 구현체
      • JVM과 Java 프로그램 개발에 필수적인 도구와 라이브러리 API를 정의함.
    • Java 프로그램에 개발에 필요한 JVM, 라이브러리 API, 컴파일러 및 개발 도구가 포함
    • JRE + 개발에 필요한 도구