본문 바로가기

공부방/JAVA

JVM 구조

 

 

클래스 로더 시스템


  • .class 에서 바이트코드를 읽고 메모리에 저장
  • 하는 역할은 크게 세가지로 나눌 수 있다.
  • 로딩: 클래스 파일에서 바이트 코드를 읽어오는 과정
  • 링크: 레퍼런스를 연결하는 과정 (링크도 크게 세가지로 나눌 수 있다.)
  • 초기화: static 값들 초기화 및 변수에 할당

 

- 보충 개념


1. class 파일은 어디에 있을까? intellij에서 class 파일 찾기

 

class파일의 위치는 target/classes 아래 디렉터리에서 확인할 수 있다.

원래는 컴파일 되어있는 바이트 코드가 있어야 하는데 intellij 에서 확인하면 바이트 코드가 아닌 것을 확인할 수 있다.

javap 같은 것을 사용해서 우리 눈에 조금 더 사람이 읽을 수 있는 코드로 보여주고 있는 것이라고 보면 된다.

(바이트 코드를 디 컴파일 해서 보여주는 것이라고 보면 되겠다.)

 

javap -c 클래스 파일 명령어를 입력 하면 바이트 코드를 확인할 수 있다.

 

 

2. static 값들 초기화 및 변수에 할당하는 역할이란?

 

클래스 로더 시스템에서 static 값들 초기화 및 변수에 할당 한다 라는 개념.

아래와 같이 static 한 변수를 선언하고, 값을 변수에 할당하고 다른 클래스에서 static 변수를 사용할 수 있게 한다.

 

메모리


메모리는 복잡해 보일 수 있는데 크게 다섯가지 영역으로 나눠져 있다.

이중에서 가장 중요한 것은 메소드 영역이라고 보면 된다.

  • 메소드 영역에는 클래스 수준의 정보 (풀패키지 경로를 포함한 클래스 이름, 부모 클래스 이름, 메소드, 변수) 저장. 공유 자원이다. (다른 영역에서도 참조할 수 있는 정보라는 것이다.), 클래스 정보 저장
  • 힙 영역에는 객체를 저장. 공유 자원이다.
  • 스택 영역에는 쓰레드 마다 런타임 스택을 만들고, 그 안에 메소드 호출을 스택 프레임이라 부르는 블럭으로 쌓는다. 쓰레드 종료하면 런타임 스택도 사라진다. (에러 메세지 로그가 스택으로 나오는데 이때 보여지는 것이 스택에서 나오는 것이다.)
  • PC(Program Counter) 레지스터: 쓰레드 마다 쓰레드 내 현재 실행할 instruction의 위치를 가리키는 포인터가 생성된다.
  • 네이티브 메소드 스택 : 쓰레드 마다 생기는데 네이티브 메소드 호출할 때 사용하는 별도의 메소드 스택이다.
    • 네이티브 메소드 라이브러리를 쓰려면 JNI를 통해야하는데 JNI를 사용하는 메소드 스택은 네이티브 메소드 스택에 저장된다.
    • JNI가 구현된 것을 네이티브 메서드 라이브러리라고 보면 된다.
    • 라이브러리는 항상 JNI를 통해야 한다.
    • 네이티브 메서드라고 함은 메소드에 native라고 붙어있고 구현을 java가 아닌 c나 c++로 구현한 것이다.
    • https://javapapers.com/core-java/java-jvm-run-time-data-areas/#Program_Counter_PC_Register

* 힙영역과 메소드 영역은 모드 쓰레드에서 공용으로 사용하고, 스택 pc 네이티브 메소드 스택은 특정 쓰레드에 국한된 정보이다. 다른 쓰레드끼리 정보를 공유하지 않는다.

실행 엔진


  • 인터프리터: 바이트 코드를 한줄 씩 실행.
    • 바이트코드는 인터프리터가 이해할 수 있다. 한줄 한줄 실행하면서 네이티브 코드로 바꿔준다.
    • 한줄 마다 바이트 코드를 네이티브 코드로 컴파일 해서 실행하는 것이다.
    • 똑같은 코드가 여러개 나와도 매번 네이티브 코드로 바꾸는 것이 비효율 적이기 때문에
    • 반복적인 코드가 나오면 JIT 컴파일러로 보낸다.
    • JIT 컴파일러는 자바 코드를 바이트 코드로 바구는 것이 아닌 바이트 코드를 네이티브 코드로 바꿔주는 것이며 반복된 코드를 찾아 미리 네이티브 코드로 바꿔주고, 인터프리터가 해당 라인에 걸리면 JIT에서 바꿔놓은 네이티브 코드를 사용하여 프로그램 효율을 높여주는 것이다.
  • JIT 컴파일러: 인터프리터 효율을 높이기 위해, 인터프리터가 반복되는 코드를 발견하면 JIT 컴파일러로 반복되는 코드를 모두 네이티브 코드로 바꿔둔다. 그 다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용한다.
  • GC(Garbage Collector): 더이상 참조되지 않는 객체를 모아서 정리한다.
    • GC 개념은 이해를 해야되는 것은 당연하며 경우에 따라 옵션을 변경해야 할 때도 있다. (customizing)
    • 프로젝트에 사용하는 GC를 알아야 하며, 어플리케이션 실행시 사용할 GC를 선택해야 할 때도 있다.
    • 가장 크게 GC를 둘로 나누면 throughput 위주의 GC 가 있고, stop the world를 줄이는 GC가 있다.
    • 서버 운영중에 굉장히 많은 객체를 사용하고 response time이 중요하다 -> stop the world를 최소화 할 수 있는 gc사용하는 것이 맞다.

JNI(Java Native Interface)


네이티브 메소드 라이브러리


  • C, C++로 작성 된 라이브러리

참고

 

- 추가 개념


1. 상위 클래스를 확인해보자.

 

아래와 같은 커맨드로 상위 클래스를 확인할 수 있다.

부모 클래스 이름 (상속 받고 있는 상위 클래스 명, ex Object.class)

 

 

2. native 메서드를 확인해보자.

 

네이티브 메서드란 말 그대로 메서드 앞에 native가 붙은 것이다.

Thread.currentThread() 라는 메서드가 있다.

이 메서드는 자바로 구현된 것이 아니다.