공부/JAVA

트러블 슈팅을 위한 JVM 공부 (1일차)

JangGiraffe 2022. 11. 7. 22:42

오늘 알게된 사실

1. java에서 (jvm의) native method를 이용해 특정 운영체제의 서비스를 확인할 수 있다.(java에서 c의 라이브러리를 호출하고 사용하는것이 가능함!)

2. java의 큰 변화는 2014년 오라클의 java인수와 java8(모던 자바) 출시 > 2018년 java11 출시 및 올해들어서 java11 기반의 프로젝트의 활성화 ! (java8 관련해서는 월말에 공부할 계획이라 java11은 좀 더 나중에 꼭 공부해보자!)

3. java8부터 jvm이 os로부터 메모리를 할당받아 쓰기보다는 os의 메모리를 사용하게 됐다(?이말이 맞나) - 아래 Heap 내용 참고

4. GC의 동작방식에 대해 알게되었고, CPU 사용량이 왜 늘어나는지를 이해했다. (아래 GC의 동작방식 참고)

5. excpetion 발생했을 때 프린트하는 스택트레이스가 jvm의 스택을 말하는거였다!

6. 나머지 교육을 마저 들으면 트러블슈팅하는데 정말 많은 도움이 될 것 같다.

 

KOSTA에서 'JVM 아키텍처 이해를 통한 자바 시스템 트러블슈팅' 교육을 들으며 정리한 내용입니다. 틀린 내용은 지적 부탁드립니다.

 

JAVA의 특징

  • 플랫폼(OS)에 자유롭고(jvm이 다 해줌) / 메모리를 관리해주고(GC) / 동적링킹(필요할 때 라이브러리를 연결) ..

JVM(java virtual machine)

  • class loader를 통해 class파일을 jvm으로 로딩
  • -> Execution engine에 의해 해석
  • -> runtime Data Area에 배치되어 프로그램이 수행됨
  • -> 필요에 따라 thread synchronization과 garbage collection 작업이 수행됨

Runtime Data Area

  • 프로세서로서 JVM이 프로그램을 수행하기 위해 OS로 부터 할당 받은 메모리 영역
  • Method Area,Heap,PC Register,JVM Stacks,Native Method Stacks이 있음
  • Thread의 공유되는 영역에 따라 2가지로 나뉜다.

모든 Thread에 공유되는 영역[Method,Heap] (JVM에 하나만 생성되는 영역이라고 보면 됨)

  1. Method Area
    • Class의 메타데이터를 저장하는 영역(Class File에서 type에 관한 메타정보를 추출해서 저장)
    • 우리가 개발한 로직,+ STATIC 전역변수가 올라가는 영역
    • JVM이 시작할 때 생성된 GC의 대상
  2. Heap
    • New키워드를 통해 생성한 객체가 저장되는 영역
    • Java7의 permanet영역(heap쪽)이 Java8부터는 Metaspace영역(native memory쪽)으로 이름 및 영역이 변경되었는데, 이를 통해 JAVA는 설치된 OS의 메모리도 전부 사용할 수 있게 되어 자바 개발자가 메모리를 좀 덜 신경쓸 수 있게 됐지만 OOM(Out of Memory)가 발생했을 때 JAVA가 실행되는 OS의 메모리도 다 사용하는 상황이 벌어질 수 있다. 이는 다음 옵션을 통해 제한할 수 있다 ! 해당 옵션이 없는 프로그램은 OS를 위험한 상황에 처하게 만들 수 있으니 반드시 주의하자. (-XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m)

GC의 동작방식

JVM 모니터링 툴을 이용해 확인한 GC의 동작방식

  • Heap영역에는 Young Generation(eden,survivor from,survivor to) 영역과 Old Generation영역이 있다.
  • 새로생성된 Object는 Eden영역에 저장되고 메서드블럭 ({})이 닫히면 해당 메서드 블럭 안에 있는 오브젝트들은 가비지컬렉션 대상이 된다.
  • Eden영역이 꽉 차면 GC가 동작하고 Eden에 있는 GC대상이 아닌 오브젝트들을 서바이벌 from->to로 옮긴다. 옮겨진 오브젝트는 번호가 매겨진다(옮겨진 횟수만큼)
  • 위 동작을 반복하다 일정 값 이상의 번호가 매겨지면 Old Generation 영역으로 해당 오브젝트가 이동된다.
  • Old Generation 영역이 가득 차면 GC가 실행되는데 이 때는 Full GC로 실행된다.
  • GC의 쓰레드 우선순위가 가장 높아서 GC가 동작할 때 다른 쓰레드가 느려진다.(서비스에 영향을 준다는 뜻)
  • Old Generation이 꽉 찼는데 GC할 오브젝트가 없다면(메모리 해소가 없다면) GC를 더 자주 호출하면서 가비지를 찾게된다. 이러면 결론적으로 OS의 CPU 사용량이 늘어나게 된다.

 

 

모든 Thread에 각각 생성되는 영역[PC Register,JVM Stacks,Native Method Stacks]

 

PC(program Counter) Register

  • Thread가 현재 실행하고 있는 주소, 다음 주소등을 기억하고 있는 애(?)

JVM Stacks

  • stack은 여러개의 stack frame으로 이루어져있음 (stack frame은 local variable section,operand stack, frame data 등등이 있다)
  • local variable section : 지역변수와 메서드,원시자료형은 해당 섹션에 직접 할당, 참조자료형은 레퍼런스값(주소값)만 할당된다. (메서드가 return될 때 원시자료형의 메모리는 직접할당됐기 때문에 바로 해소가 되는데, 참조자료형은 heap에 있기 때문에 가비지가 되고 나중에 GC에 의해 해소된다.)
  • operand stack : cpu, local variable section의 중간에서 메소드를 수행하는 데 필요한 값의 중계 역할을 한다.
    (아래 코드를 수행할 때 cpu에서 5,6 등등의 값을 가져와서 local variable section에 전달해주고 막이런역할)
    (int a,b,c; a=5;b=6;c=a+b;)
  • frame data : constant pool resolution(다이나믹 링킹),exception dispatch(예외처리 시 몇번라인으로 이동할지goto.. 처리하는애) / stack의 자료구조와 동일(lifo) / 함수의 호출과정을 스택이라고 함(excpetion 발생했을 때 프린트하는 스택트레이스가 jvm의 스택을 말하는거였다!)

 

Native Method Stacks

  • JAVA는 JNI(java native interface)를 통해 native function을 호출함.(네이티브(os)의 메서드를 말함)
  • jvm에서 지원하지 않는 특정 os의 서비스를 이용하고 싶을 때 쓴다(ex: c언어로 제작된 라이브러리를 java에서 사용하고 싶을 때)
  • 프로그래밍 시 메서드 선언부에 native 키워드를 붙혀서 프로그래밍 하는듯.

OOM이 발생할 수 있는 위치는 heap area,method area,native area가 된다.

반응형