관리 메뉴

JIHYUN JEONG

[JAVA/JVM] 메모리 구조 (부제 : 성능개선을 위한 GC의 활용) 본문

Information Technology/Performance

[JAVA/JVM] 메모리 구조 (부제 : 성능개선을 위한 GC의 활용)

StopHyun 2013. 3. 16. 11:50

이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.



JVM이란 무엇인지 대해 알아본후 JVM.EXE의 파일을 비교하여 JVM의 실행구조, 수행과정, Runtime Data Areas, 힙영역등에 대해 설명을 하겠습니다. 그리고 이를 바탕으로 가비지 컬렉션이 메모리들을 어떻게 관리하는지 알아보고 성능에 어떠한 영향을 미치는지에 대해 알아보도록 하겠습니다.





[ 서론 ]

[JVM의 구조를 이해해야 하는가?]



 - 예를 들어 시스템 프로젝트를 수행시 하루에 200만 개의 트랜잭션을 처리해야 한다면 성능의 대한 부분을 고려하지 않을수 없다. 이에 따라 자바 가상머신인 JVM 작동원리를 이해하여 트랜잭션에 대한 응답시간, 또는 처리량의 염두해두고 코딩을 해야합니다.


- 정보시스템의 설계 및 개발단계의 오류로 인한 성능 저하 문제가 약 33%(설계 오류, 아키텍처 오류, 어플리케이션 코드 오류)를 차지

하고 있으며 특히, 설계 또는 아키텍처의 오류는 개선에 따르는 비용과 시간이 타 부분에 비하여 막대하므로 정보시스템 구축 시 프로젝트 전 단계에 걸쳐 지속적으로 성능관리를 수행하고 그 결과를 검증 하는 것이 중요하다.


이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.





JVM은 정의된 Specification을 구현한 하나의 독자적인 Runtime Instance 라고 할수 있다.


JVM의 역활은 쉽게 말해 우리가 작성한 Java 프로그램, Web Application Server(WAS)등을 구별하지 않고 Java 프로그램의 범주에 들어가는 모든 것들을 실행시키게 된다. 이것은 바로 Java에서 JVM이 핵심이라고 말하는 이유


[ JVM 특징 ]

 - 스택기반의 가상머신 : 대표적인 컴퓨터 아키텍처인 인텔 x86 아키텍처나 ARM 아키텍처와 같은 하드웨어가 레지스터 기반으로 동작하는데 비해 JVM은 스택 기반으로 동작합니다. (좀 더 공부가 필요한 부분)

 - 가비지 컬렉션 : C언어에서 malloc(), free() 통해 메모리를 통제, but javaJVM이 이 기능을 해줌

 - 플랫폼에 독립적 : 프로그램 실행구조와 비교해 가면서 설명


[자바 프로그램 실행구조 ]


자바 프로그램의 실행구조

운영체제는 자바 가상머신을 실행시키고, 자바 가상머신은 자바 프로그램을 실행시키는 구조


일반적인 프로그램의 실행구조

일반적인 프로그램은 WindowsLinux 같은 운영체제 위에서 실행이됨


이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.




[JVM의 기본적인 수행과정]

 1. Class Loadder System을 통해 Class파일들을 JVM으로 로딩한다

 2. 로딩된 Class 파일들은 Execution Engine을 통해 해석된다.

 3. 해석된 프로그램은 Runtime Data Areas에 배치되어 실직적인 수행이 이루어지게 된다. 이러한 실행 과정 속에서 JVM은 필요에 따라 Thread Synchronization Garbage Collection 같은 관리작업을 수행하게 된다.


[ 자바 프로그램 ]

Java에서 프로그램을 실행한다는 것은 Class파일을 JVM으로 로딩하고 Bytecode를 해석(Interpret)하는 작업은 물론, 메모리 등의 리소스를 할당하고 관리하며 정보를 처리하는 일련의 작업들을 포괄한다. 이 때 JVM은 쓰레드 관리 및 Gabage Collection과 같은 메모리 재생 작업도 수행한다.


[ 일반적인 프로그램 ]


1. 로딩

윈도우 시스템에서 실행파일은 PE(Portable Excutable)파일 형식을 가지고 있습니다.

Visual studio컴파일하면 .exe 의 확장자를 가진 파일이 생성되게 됩니다.

바로 이 파일이 PE파일형식을 가지고 있습니다.

프로그램 실행 명령이 내려지면 OSPE파일의 header부분을 분석해서 프로그램의 진입지점을 적절하게 메인 메모리에 로딩하게 한 됩니다.

그 후 프로그램의 명령에 따라 필요한 순차적으로 명령어들을 로딩하게 됩니다.

 

2. 패치(Instruction Fetch)

메모리에 로딩된 프로그램은 CPU를 동작시키기 위한 명령어인 인스트럭션(Instruction)의 집합이라고 할 수 있습니다.

컴파일이라는 것은 결과적으로 우리의 소스 코드를 CPU가 이해할 수 있는 인스트럭션으로 변화시켜 주는 것입니다.

프로그램이 실행되기 위해서는 메모리에 로딩된 인스트럭션들을 순차적으로 CPU읽어들여야 합니다.

이러한 과정을 인스트럭션 패치라고 합니다.

 

3. 디코딩(Instruction Decoding)

그림 2번의 8d 44 24 0c 16진수로 표현 되었을 뿐 0,1 로 구성된 바이너리 코드입니다.

실행을 위해서는 0,1로 구성된 바이너리 코드를 각 필드별로 분해하여 어떤 종류의 연산을 수행 할 것인지를 결정해야 하고

연산에 필요한 연산자를 레지스터에 인가시키는 작업이 필요합니다.

이러한 작업을 디코딩이라고 합니다.


 4. 실행(Execution)

디코딩 과정에서 수행 될 연산의 종류는 연산코드의 형식으로 CPU에서 실질적인 연산을 수행하는 산술논리 연산장치(arithmetic-logic unit) : ALU 에 입력됩니다.

ALU는 연산코드에 맞춰서 레지스터에 저장된 연산자들을 이용하여 연산을 수행하게 됩니다.

하나의 인스트럭션이 실행을 마치면 다시 새로운 인스트럭션을 패치해 오게 되는 과정을 반복하게 됩니다.

이 과정을 좀더 자세하게 보면 이런 그림인 것입니다.



이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.





- Runtime Data AreasProcess로서의 JVM 프로그램을 수행하기 위해 OS로부터 할당 받는 메모리 영역


- Runtime Data AreasJava Application, 특히 Web Application Server(WAS)를 사용할 때 가장 빈번하게 성능문제가 발생하는 영역(Memory Leak, Garbage Collection)

- Runtime Data Area는 각각의 목적에 따라 5개 영역으로 나뉨

- PC Register와 두개의 Stack영역은 각 Thread 별로 생성이 되고 Method AreaHeap은 모든 Thread에게 공유된다.

  1) PC Registers : 프로그램의 실행은 CPU에서 명령어, 인스트럭션(Instruction)을 수행하는 과정으로 이루어진다. CPU는 이러한 Intruction을 수행하는 동안 필요한 정보를 레지스터라고 하는 CPU 내의 기억장치를 사용한다. 연산의 결과값을 메모리로 전달하기 전에 CPU 어딘가에 잠시 머무르도록 해야 한다. 이 때 사용하는 CPU 어딘가에 잠시 머무르도록 해야한다. 이때 사용하는 cpu내의 기억장치를 레지스터

 

2) JVM Stack : Thread의 수행 정보를 기록하는 Frame을 저장하는 메모리 영역


3) Native Method Stacks : Javajava 외의 언어로 작성된 프로그램, API 툴킷 등과의 통합을 쉽게 하기 위하여 JNI (Java Native Interface)라는 표준 규약을 제공, 다시 말해 Native Code로 되어 있는 Function의 호출을 Java프로그램 내에서 직접 수행할 수도 있고 그 결과 값을 받아 올 수도 있게 된것이다,

  

4) Method Area : 모든 Thread 들이 공유하는 메모리 영역이다. 이 영역은 Load Type을 저장하는 논리적 메모리 공간으로 정의할수 있다. 여기서 Type이란 ClassInterface를 의미

  

5) Java HeapJava Heap은 단지 Instance(또는 Object) Array 객체 두 가지 종류만 저장되는 공간. 자바 힙은 모든 Thread들에 의해 공유된다.


[ 정리된 Runtime areas]


런타임 데이터 영역은 JVM이라는 프로그램이 운영체제 위에서 실행되면서 할당받는 메모리 영역이다. 런타임 데이터 영역은 6개의 영역으로 나눌 수 있다. 이중 PC 레지스터(PC Register), JVM 스택(JVM Stack), 네이티브 메서드 스택(Native Method Stack)은 스레드마다 하나씩 생성되며 (Heap), 메서드 영역(Method Area), 런타임 상수 풀(Runtime Constant Pool)은 모든 스레드가 공유해서 사용한다.


PC 레지스터: PC(Program Counter) 레지스터는 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 생성된다. PC 레지스터는 현재 수행 중인 JVM 명령의 주소를 갖는다.


JVM 스택: JVM 스택은스레드마다 하나씩 존재하며 스레드가 시작될 때 생성된다. 스택 프레임(Stack Frame)이라는 구조체를 저장하는 스택으로, JVM은 오직 JVM 스택에 스택 프레임을 추가하고(push) 제거하는(pop) 동작만 수행한다. 예외 발생 시 printStackTrace() 등의 메서드로 보여주는 Stack Trace의 각 라인은 하나의 스택 프레임을 표현한다.

네이티브 메서드 스택 : 자바 외의 언어로 작성된 네이티브 코드를 위한 스택이다. , JNI(Java Native Interface)를 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택으로, 언어에 맞게 C스택이나 C++스택이 생성된다.


메서드 영역 : 메서드 영역은 모든 스레드가 공유하는 영역으로 JVM이 시작될 때 생성된다. JVM이 읽어 들인 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드와 메서드 정보, Static변수, 메서드의 바이트코드 등을 보관한다. 메서드 영역은 JVM 벤더마다 다양한 형태로 구현할 수있으며, 오라클 핫스팟 JVM (HotSpot JVM)에서는 흔히 Permanent Area, 혹은 Permanent Generation(PermGen)이라고 불린다. 메서드 영역에 대한 가비지 컬렉션은 JVM 벤더의 선택 사항이다.


런타임 상수 풀 : 클래스 파일 포맷에서 constant_pool 테이블에 해당하는 영역이다. 메서드 영역에 포함되는 영역이긴 하지만, JVM 동작에서 가장 핵심적인 역활을 수행하는 곳이기 때문에 JVM명세에서도 따로 중요하게 기술한다. 각 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블이다. , 어떤 메서드나 필드를 참조할 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 참조한다.


: 인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션 대상이다. JVM성능 등의 이슈에서 가장 많이 언급되는 공간이다. 구성 방식이나 가비지 컬렉션 방법 등은 JVM 벤더의 재량이다.














이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.

[JVM의 기본적인 수행과정]

 1. Class Loadder System을 통해 Class파일들을 JVM으로 로딩한다

 2. 로딩된 Class 파일들은 Execution Engine을 통해 해석된다.

 3. 해석된 프로그램은 Runtime Data Areas에 배치되어 실직적인 수행이 이루어지게 된다. 이러한 실행 과정 속에서 JVM은 필요에 따라 Thread Synchronization Garbage Collection 같은 관리작업을 수행하게 된다.


[ 자바 프로그램 ]

Java에서 프로그램을 실행한다는 것은 Class파일을 JVM으로 로딩하고 Bytecode를 해석(Interpret)하는 작업은 물론, 메모리 등의 리소스를 할당하고 관리하며 정보를 처리하는 일련의 작업들을 포괄한다. 이 때 JVM은 쓰레드 관리 및 Gabage Collection과 같은 메모리 재생 작업도 수행한다.


[ 일반적인 프로그램 ]


1. 로딩

윈도우 시스템에서 실행파일은 PE(Portable Excutable)파일 형식을 가지고 있습니다.

Visual studio컴파일하면 .exe 의 확장자를 가진 파일이 생성되게 됩니다.

바로 이 파일이 PE파일형식을 가지고 있습니다.

프로그램 실행 명령이 내려지면 OSPE파일의 header부분을 분석해서 프로그램의 진입지점을 적절하게 메인 메모리에 로딩하게 한 됩니다그 후 프로그램의 명령에 따라 필요한 순차적으로 명령어들을 로딩하게 됩니다.

 

2. 패치(Instruction Fetch)

메모리에 로딩된 프로그램은 CPU를 동작시키기 위한 명령어인 인스트럭션(Instruction)의 집합이라고 할 수 있습니다.

컴파일이라는 것은 결과적으로 우리의 소스 코드를 CPU가 이해할 수 있는 인스트럭션으로 변화시켜 주는 것입니다.

프로그램이 실행되기 위해서는 메모리에 로딩된 인스트럭션들을 순차적으로 CPU읽어들여야 합니다.

이러한 과정을 인스트럭션 패치라고 합니다.

 

3. 디코딩(Instruction Decoding)

그림 2번의 8d 44 24 0c 16진수로 표현 되었을 뿐 0,1 로 구성된 바이너리 코드입니다.

실행을 위해서는 0,1로 구성된 바이너리 코드를 각 필드별로 분해하여 어떤 종류의 연산을 수행 할 것인지를 결정해야 하고

연산에 필요한 연산자를 레지스터에 인가시키는 작업이 필요합니다.

이러한 작업을 디코딩이라고 합니다.


 4. 실행(Execution)

디코딩 과정에서 수행 될 연산의 종류는 연산코드의 형식으로 CPU에서 실질적인 연산을 수행하는 산술논리 연산장치(arithmetic-logic unit) : ALU 에 입력됩니다.

ALU는 연산코드에 맞춰서 레지스터에 저장된 연산자들을 이용하여 연산을 수행하게 됩니다.

하나의 인스트럭션이 실행을 마치면 다시 새로운 인스트럭션을 패치해 오게 되는 과정을 반복하게 됩니다.

이 과정을 좀더 자세하게 보면 이런 그림인 것입니다.



이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.











 할당된 메모리를 누가 어떻게 해제 될까바로 Garbage Collector가 Garbage Collection을 통해 메모리를 해제한다.

  - 메모리의 해제란 Heap 이나 Method Area에 있는 특정한 Object를 Memory에서 삭제한다는 의미


 Java에서는 개발자가 프로그램 코드로 메모리를 명시적으로 해제하지 않기 때문에 가비지 컬렉터(Garbage Collector)가 더 이상 필요 없는 (쓰레기객체를 찾아 지우는 작업을 한다.


 GC에 대해서 알아보기 전에 알아야 할 용어

stop-the-world, GC을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다.


 GC만들어진 2가지 전제조건 

대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.

오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.










이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.










GC에 대해서 알아보기 전에 알아야 할 용어가 있다. 바로 'stop-the-world'이다. stop-the-world, GC을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다. stop-the-world가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다. 어떤 GC 알고리즘을 사용하더라도 stop-the-world는 발생한다. 대개의 경우 GC 튜닝이란 이 stop-the-world 시간을 줄이는 것이다.


What makes a GC slow?

Although it is called Garbage Collection the amount of collected garbage has only indirect impact on the speed of a run. What actually determines this is the number of living objects. To understand this let’s take a quick look at how Garbage Collection works.

Every GC will traverse all living objects beginning at the GC roots and mark them as alive. Depending on the strategy it will then copy these objects to a new area (Copy GC), move them (compacting GC) or put the free areas into a free list. This means that the more objects stay alive the longer the GC takes.The same is true for the copy phase and the compacting phase. The more objects stay alive, the long it takes. The fastest possible run is when all objects are garbage collected!

With this in mind let’s have a look at the impact of garbage collections.


[GC절차 ]


1. 자바 객체는 Eden 영역에 태어납니다. 이를 memory 할당(allocation)이라 합니다. Eden은 모든 Java 객체의 고향이죠.


2. Eden 영역이 간당간당해져서 GC 필요성이 생기면 살아야 할 놈은 S0으로 복사합니다


3. Eden 영역을 다 날립니다(사실은 이때 S1 영역도 같이 날립니다)!


4. EdenJava 객체들이 태어납니다.


5. 그러다 또 Eden이 간당간당하면 이번엔 살아야 할 놈들을 S1으로 복사합니다. 이 땐 S0에서도 살아야 할 놈들은 S1으로 복사합니다.


6. 또 한 번 EdenS0를 다 날립니다(... Java 객체의 대규모 학살...)!



이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.











그렇다면 ?? "모든 Java 기반의 서비스에서 GC 튜닝을 해야 할까?"


결론부터 이야기하면 모든 Java 기반의 서비스에서 GC 튜닝을 진행할 필요는 없다.


GC 튜닝이 필요 없다는 이야기는 운영 중인 Java 기반 시스템의 옵션과 동작이 다음과 같다는 의미이다.


- Xms 옵션과 ?Xmx 옵션으로 메모리 크기를 지정했다.

- server 옵션이 포함되어 있다.

- 시스템에 Timeout 로그와 같은 로그가 남지 않는다.


다시 말하면, 메모리 크기도 지정하지 않고 Timeout 로그가 수도 없이 출력된다면 여러분의 시스템에서 GC 튜닝을 하는 것이 좋다


이번엔 JAVA의 JVM(메모리) 구조 (부제 : 성능개선을 위한 GC의 활용) 에 대해 알아 보겠습니다.

이 글이 도움이 되셨으면, 아래의 클릭을 통해 커피 한잔 후원 부탁드립니다. 감사합니다.


  Buy Me A Coffee

'Information Technology > Performance' 카테고리의 다른 글

정보시스템 성능관리 지침  (0) 2012.07.22
Comments