Programming/Java \ Spring

🔥자바스터디🔥 자바의 정석 CH1 자바언어의 특징, JVM, 자바 컴파일러

1. 자바언어의 특징

 

자바의 정석에 나열된 자바언어의 특징으로 운영체제에 독립적인 부분이 가장 먼저 언급되어있는데,

이는 자바가상머신(JVM)을 통해서 운영체제와 소통하기 때문에 자바언어 자체는 운영체제와 독립되어 운영되고,

JVM은 운영체제에 종속적이라 어떻게 보면 세트메뉴와 같은데 독립적이라고 표현하는게 맞는지 잘 모르겠다.

 

이외의 특징으로 객체지향언어이다 - 처음 이 부분을 보았을땐 요즘은 다 객체지향언어이지 않은가 생각했었는데,

그 뒤의 객체지향개념의 특징으로 언급된 상속, 캡슐화, 다형성 부분을 다루는 언어는 내가 알고 있는 언어중에는 없는것 같다. (알고있는 프로그래밍 언어 - 자바, 자바스크립트, 파이썬 정도?)

 

비교적 배우기 쉽다. - C, C#, C++ 등등 C로 시작하는 언어는 게임, IOT 등등 기계와 더 관련이 깊은 것같고 어렵다고 한다 그에 비해 자바는 기존에 개발된 언어들의 장점들을 취합하여 만들어져 객체지향언어의 특징인 재사용성과 유지보수의 용이성 등 객체지향개념을 보다 쉽게 이해하고 활용할수 있다.

(쉽다지만 노란병아리들은 아직 어렵다)

 

자동 메모리관리 - 자바로 작성된 프로그램이 실행되면 가비지컬렉터가 자동적으로 메모리 관리를 해주기 때문에 따로 관리하지 않아도 된다고 하는데 왜 자꾸 개발용 컴퓨터가 느려지는 걸까?? 

 

네트워크와 분산처리 지원, 멀티쓰레드 지원 - 다양한 라이브러리(JAVA API) 활용

 

동적 로딩 지원 - 프로그램 실행 즉시 모든 클래스가 로딩되지 않고 필요 시점에 클래스를 로딩하여 가볍게 사용할 수 있다. 

 

 

2. 자바어플리케이션 구동 흐름

 

JIT와 컴파일러를 따로 구분하는게 아니라 JIT방식의 컴파일러를 사용함으로써 속도문제를 개선했다고 합니다.

여기서 알아야되는 부분이 자바어플리케이션의 구동 흐름입니다.

보통의 어플리케이션의 흐름이 컴퓨터-OS-어플리케이션,
자바 어플리케이션은 컴퓨터-OS-JVM-어플리케이션 

OS에서 JVM으로 전달될때 하드웨어기계어를 해석하기 위해 인터프리터(바이트코드(JVM이 이해할수 있는 언어) 해석)가 가동되고 인터프리터에 부스터를 달아준게 JIT컴파일러입니다(자바소스코드 >> 바이트코드)

JVM에서 OS, OS에서 JVM 으로 이동시 바이트코드로 변환해주는 컴파일러가 없었다면 인터프리터가 혼자 다 일해야되서 속도가 매우 느렸답니다. 그래서 만들어진게 JIT 컴파일러


 

🔥자바스터디 1주차 과제🔥

 

* JVM이란 무엇인가

 

     자바 어플리케이션이 구동하는 가상머신 /

     JVM은 JAVA BYTE CODE만 이해할 수 있다.

     따라서 JVM이 이해할수 있도록 JAVA Compiler가 소스파일(.java)을 java byte code(.class)로 변환한다.

     JAVA bytecode는 OS에서 이해할수 없기 때문에 인터프리터(java.exe)를 통해 OS에서 구동할수 있도록 기계어로 변환한다.

     이 과정을 거치기 때문에 C언어와 같은 네이티브 언어에 비해 속도가 느렸지만,

     JIT(Just In Time)컴파일러 구현을 통해 속도를 개선시켰다.

* 컴파일 하는 방법 / 실행하는 방법

코드작성!(Hello.java) System.out.println("헬로월드!") >> 자바컴파일러(javac.exe) - Hello.class 생성

>> 자바인터프리터(java.exe) >> "헬로월드!" 출력

   ** 자바인터프리터 java.exe 에 의해 프로그램이 실행되려면! 'public static void main(String[] args){}' 메소드가 필요하다

 

    1. java 소스코드 작성(.java)

    2. build를 진행하면 자바컴파일러(javac.exe)를 통해 .class(java bytecode 생성)

    3. java byte code(.class)는 클래스 로더에 의해 JVM 내로 로드

       (이를 위해 main 메소드를 포함한 class를 소스파일 내에 가지고 있어야한다.)

    4. 실행 엔진(Execution Engine)에 의해 기계어로 해석되어 메모리(Runtime Data Area)에 배치된다.

 

* 바이트코드란 무엇인가

    바이트코드는 특정 하드웨어(OS)가 아닌 자바가상머신(JVM)에서 돌아가는 실행 프로그램을 위한 이진 표현법이다.

    JVM이 사용자가 작성한 .java 소스 코드 파일을 운영체제에 실행 가능한 명령어 집합 파일로 컴파일 하는 과정 중에서 필요한 코드

    자바 컴파일러에 의해 변환되는 코드 명령어읭 크기가 1byte라서 자바 바이트 코드라고도 불린다.

 

 

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

    

JIT 컴파일 (just-in-time-compilation) 또는 동적 번역(dynamic translation)은 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법이다.

전통적인 입장에서 컴퓨터 프로그램을 만드는 방법은 두가지가 있는데, 인터프리트 방식과 정적 컴파일 방식으로 나눌 수 있다.

이 중 인터프리트 방식은 실행 중 프로그래밍 언어를 읽어가면서 해당 기능에 대응하는 기계어 코드를 실행하며,

반면 정적 컴파일 방식은 실행하기 전에 프로그램 코드를 기계어로 번역한다.

 

실행엔진에는 Interpreter와 JIT(Just-In-Time) Compiler가 있다. Interpreter는 바이트 코드를 한줄씩 읽기 때문에 실행이 느리다.

이러한 단점을 보완하기 위해 나온것이 JIT Compiler이다.

인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일 하고 더이상 인터프리팅 하지 않고 해당 코드를 직접 실행한다.

JIT 컴파일러에 의해 해석된 코드는 캐시에 보관하기 때문에 같은 함수가 여러번 불릴 때 매번 기계어 코드를 생성하는 것을 방지한다.

하지만 인터프리팅 방식보다는 훨씬 오래 걸리므로 한번만 실행하면 되는 코드는 인터프리팅하는것이 유리하다.

 

Interpreter : 자바 바이트 코드를 한줄 씩 실행, 여러번 실행하는 환경에서는 다소 느림

JIT Compiler : Interpreter의 단점을 보완, 전체 바이트 코드를 컴파일, 캐시 사용으로 한번 컴파일하면 다음에는 빠르게 수행

 

장점

1. 생성되는 코드의 안정성
	
    Java가 수행중 만들어내는 기계어 코드는 안전한 공간(sandBox)안에서 돌아가기 때문에 외부 해킹에 안전
    
2. 동작하는 메모리 공간의 안전성
	
    모든 자바 객체들은 Heap이라는 독립적인 공간에서만 수행
    다른 Process 와 다른 메모리 공간을 사용하기 때문에 Stack overflow에 강함
    
3. 최적화 재사용에 유일한 관련 클래스간 상속구조
	
    메모리 위치상 가깝게 관련된 객체와 메소드들을 위치시킨다.
    method inlining 같은 성능을 높이기 위한 테크닉들이 자바에서 효율적으로 작동
    
4.동적 최적화와 그것에 대한 취소, 재 최적화 가능
	
    static 언어와 다르게 dynamic class loading으로 어떤 방식으로든 수행중 변경 가능 
    compiler를 통한 최적화가 수시로 이루어 진다.

더보기

자바 Compiler 기술들

  • Hot Spot Detection
    • JVM이 ByteCode를 해석하다가 루프 등을 만나 몇번이나 중복적인 해석이 이루어진다고 판단되면 Byte코드를 기계어로 직접 컴파일하는 방식
    • 기존의 모든 기본 코드를 수행전에 컴파일 하는 방식은 수행 자체는 빠르지만 프로그램 크기가 커지고 기기별 이식성이 떨어지기도 한다.
  • Method inlining
    • 클래스 안에서 사용된 다른 클래스에 대해 method inlining을 수행함으로서 다른 메모리 공간에 있는 메소드에 대해 호출하는 것을 피할 수 있다.
    • 이걸 취소할 수도 있다.
  • reflection
    • 객체를 명시적으로 코드에서 new하지 않아도 임의의 객체를 동적으로 생성하고 메소드를 호출할수 있는 reflection은 자바 동적 클래스로딩의 핵심

JIT

핫스팟 JVM의 핵심 컴파일 방법중 하나로 먼저 인터프리터가 동작하여 코드를 실행

일정시간 동안 인터프리터가 코드를 해석하며 컴파일하기에도 충분할 정도로 자주 호출되는 메소드가 무엇인지 알아내고 해당 메소드만 컴파일

위의 컴파일 장점이 되는 모든 기능들은 자바 1.6 이후의 HotSpot 엔진의 성능향상의 덕이다.

HotSpot이란 Sun Microsystem사의 Java 엔진 이름이다. Java VM의 엔진은 다양하지만 크게 HotSpot(Sun/Oracle), J9(IBM), JRocket(Oracle) 정도가 기업용자바 환경에서 주로 사용되는 것들이다. JRocket은 서버쪽 성능개선에 집중된 것으로 HostSpot에 그 핵심기능이 옮겨져있기에 현재 대새는 Oracle Hotspot이다. HotSpot은 오픈소스 자바 프로젝트인 OpenJDK의 JVM엔진이기도 하다.

–Tips–

interpreter가 수행된다음에는 프로그램에 대해 더욱 많은 정보를 저장하면서 분석할수 있다는 점이다. 어느 지점이 hot spot인지도 monitor링 될 뿐만아니라 어느 함수가 어느 함수를 부르고 있는지도 명확하게 파악될수 있다. 자바 기반의 어플리케이션이 디버깅에 매우 유리한 이유이기도 하다.

Client Compiler

클라이언트 모드에서 동작하는 컴파일러는 주로 프로그램의 시작시간을 최소화하는데에 집중한다.

  • 클라언트 모드 총 세단계
    1. 바이트코드를 해석해서 최적화를 쉽게 하기 위해, HIR이라고 하는 정적인 바이트코드 표현을 만듬
    2. HIR로부터 플랫폼에 종속적인 중간표현식 (LIR) 을 만듬
    3. LIR을 사용해 기계어 생성
  • 클라이언트 모드 JIT의 특징은 바이트코드로부터 최대한 많은 정보를 뽑아내어 실제 동작하는 코드 블럭에 대해 최적화를 집중하는 것이다.
  • 전체적인 최적화에는 큰 관심이 없다.

Server Compiler

서버모드의 Jit compiler는 부분적인 코드 실행보다 전체적인 성능 최적화에 관점을 둔다.

  1. 일반적인 컴파일러 최적화 기술들을 이용해 일단 코드들을 최적화 한다.
    • 죽은 코드 삭제(Dead Code Elimination), loop 변수의 끌어올리기(Loop invariants hoisting), 공통 부분식 제거(Common Subexpression Elimination), 상수 지연(Constant propagation), 전역 코드 이동(Global Code motion) 등
  2. 자바에 최적화된 최적화를 수행한다.
    • Null Check 삭제, 배열의 Range Check 삭제, 예외처리 경로 최적화.
    • 대단위 RICS 레지스터들을 최대한 활용하기 위한, Graph연산을 통한 register할당
    • 이런 과정을 통해 상대적으로 느린 속도로 JIT이 수행된다. 하지만 코드의 수행은 더욱 빠르다.

* JVM 구성 요소

 

   - 클래스 로더, Runtime Data Areas(프로그램 실행중 데이터가 머무는 메모리), Execution Engine(실행엔진)

   1. Class Loader

        어플리케이션이 실행되면 java byte code(.class)에서 바이트코드를 읽어서 JVM 내 메모리에 저장

       

   2. Runtime Data Areas

        객체를 저장하는 Heap과 Method는 모든 쓰레드가 공유하고 그 외는 각 쓰레드마다 생성된다

        - PC Register : CPU가 명령을 수행하는 동한 필요한 정보를 저장

        - JVM Stack : Thread가 시작될 때 생성되며 Method와 Method 정보 저장

        - Native Method Stact : Java 이외의 언어로 작성된 native 코드를 위한 Stack(JNI)

        - Method Area : 모든 쓰레드가 공유하는 메모리 영역

                              (클래스, 인터페이스, 메소드, 필드, Static 변수등의 바이트 코드 등을 보관)

        - Heap : 런타임시 동적으로 할당하여 사용하는 영역 class를 통해 객체를 생성하면 Heap에 저장됨

 

    3. Execution Engine

        Class Loader를 통해 JVM 내의 Runtime Data Areas에 배치된 바이트 코드는 Execution Engine에 의해 실행

        (바이트 코드를 명령어 단위로 읽어서 실행)

 

     4. Garbage Collector

        Heap 메모리 영역에 생성된 객체들 중에 참조되지 않은 객체들을 제거하는 역할을 한다. GC의 동작시간은 정해져있지 않다.

        GC를 수행하는 동안 GC Thread를 제외한 다른 모든 Thread는 일시정지상태가 된다.

        (Full GC가 일어날 경우 모든 쓰레드가 정지하면 심각한 일이 일어날 수 있다)

* JDK와 JRE의 차이

 

      A. JRE(Java Runtime Environment) - 자바 애플리케이션의 실행 환경

          이미 컴파일된 자바 애플리케이션의 모듈(JAR 파일과 클래스 파일 등)을 이용하여 실행할 수 있다.

     

      B. JDK(Java Development Kit) - 자바 애플리케이션의 개발 환경

          실행 환경뿐만 아니라 소스 파일의 컴파일러 및 디버거 등 자바 애플리케이션을 개발하기 위한 도구가 포함되어 있다.

          애플리케이션을 JRE가 있으면 작동시킬수 있지만 디버깅 등을 해야될 경우 jdk가 필요하다.

 

 

 

    

 

참고 : 자바의 정석 - 남궁성 저 

 

 

league3236/startJava

java back-end study 입니다. 국내에서 python, node.js 보단 spring 위주의 공부가 좀더 이점이 많을 것 같아 계속하여 스터디하려고합니다. - league3236/startJava

github.com

 

JVM

JVM JVM이란 JAVA Virtial Machine의 약자로 Java Byte Code를 OS에 맞게 해석해주는 역할을 하는 가상머신

jeongjin984.github.io