대메뉴 바로가기 본문 바로가기

데이터 기술 자료

데이터 기술 자료 상세보기
제목 Runtime Data Areas
등록일 조회수 5064
첨부파일  

Runtime Data Areas



㈜엑셈 컨설팅본부 /APM팀 임 대호

Runtime Data Area 구조

Runtime Data Area 는 JVM 이 프로그램을 수행하기 위해 할당 받는 메모리 영역이라고 할 수 있다 . 실제 WAS 성능 문제에 직면했을 때 , 대부분의 문제점은 Runtime Data Area 에서 발생 하는 경우가 많다 . Memory Leak 이나 Garbage Collection 인 경우가 그 예이다 . 이러한 성능 문제가 발생할 시 이 문제가 왜 발생한 것인지 어디에서 발생한 것인지 확인하는 것은 쉽지 않다 . 이러한 경우 Runtime Data Area 의 아키텍처를 공부하는 것이 해당 문제를 분석하는데 큰 도 움이 될 것이다 .

Runtime Data Area 는 크게 다섯 가지 영역으로 나뉘게 된다 . 그것은 PC Register, Java Virtual Machine Stacks, Native Method Stacks, Method Area, Heap 이다 . 각 Thread 별로 생기는 영역은 P C Register, Java Virtual Machine Stacks, Native Method Stacks 이고 , 모든 Thread 가 공유하는 영역은 Method Area 와 Heap 이다 .



PC Register

Java 의 PC Register 는 CPU 내의 기억장치인 레지스터와는 다르게 작동한다 . Register - Base 가 아닌 Stack - Base 로 동작한다 . PC Register 는 각 Thread 별로 하나 씩 존재하며 현재 수행 중인 Java Virtual Machine Instruction 의 주소를 가지게 된다 . 만일 Native Method 를 수행 한다면 PC Register 는 Undefined 상태가 된다 . 이 PC Register 에 저장되는 Instruction 의 주 소는 Native Pointer 일 수도 있고 Method Bytecode 일 수도 있다 . Native Method 를 수행할 때에는 JVM 을 거치지 않고 API 를 통해 바로 수행하게 된다 . 이 는 Java 는 Platform 에 종속 받 지 않는 다는 것을 보여준다 .


Java Virtual Machine Stacks

Java virtual Machine Stacks 은 Thread 의 수행 정보를 Frame 을 통해서 저장하게 된다 . Java Virtual Machine Stacks 는 Thread 가 시작될 때 생성되며 , 각 Thread 별로 생성이 되기 때문에 다른 Thread 는 접근할 수 없다 . 대표적으로 Local variable 를 가진다 .



Java Virtual Machine Stacks 에서 현재 수행하고 있는 Frame 을 Current Frame 이라고 한다 . Stack Frame 에는 Method 의 Parameter variable, Local variable 과 연산 결과를 저장하게 된다 .


Stack Frame

Stack Frame 은 Thread 가 수행하고 있는 Method 단위를 기록하는 곳이다 . Method 의 상태 정보를 저장하는 Stack Frame 은 크게 세가지 영역으로 나뉜다 . 그것은 Local Variable Section, Operand Stack, Frame Data 이다 . Stack Frame 의 크기는 컴파일 때 결정이 난다 .


Local Variable Section

Local Variable Section 은 Method 의 Parameter Value 와 Local Variable 을 저장한다 . Local Variable Section 은 0 부터 시작하는 array 형 인덱스를 가지는데 parameter value 부터 할당 된다 . Local Variable 은 순서가 정해져 있지 않다 . 또한 만약 사용되지 않으면 할당되지 않을 수 도 있다 . Parameter Value 와 Local Variable 가 Primitive Type 인 경우 (ex int 형 ) 는 고정된 크기로 할당된다 . 하지만 String 이나 Array 같은 객체는 가변크기이므로 Reference 를 갖는다 .


Java source

class Test { public int tes tMethod (int a, char b, long c, float d, object e, double f, String g, byte h, short I, Boolean j) {return 0; }


testMethod 는 10 개의 Parameter 변수를 가진다 . Local Variable Section 에서는 그림 6 과 같이 할당 받게 된다 . 여기서 눈 여겨 봐야 할 것은 long 형과 double 형의 경우 array 를 두 개 씩 사용한다는 것이다 . c h ar, byte, short, b oolean 형으로 선언한 것은 Local Variable Section 에는 모두 int 형으로 할당 된다는 것이다 . 만약 변수를 선언할 때 Inteager 형과 int 형 중 어느 것이 성능에 더 유리할 것인가 ? int 형이 성능에 더 유리하다 그 이유는 int 형은 Java Vi rtual Machine Stack 에 저장되는 반면 Inteager 형은 Heap 에 저장이 되기 때문에 (reference) Heap 까지 찾아가는 비용이 더 들게 되기 때문이다 .

0 번 Entry 의 hidden this 는 선언한 적이 없는 변수임에도 불구하고 0 번 Entry 에 저장이 되어 있다 . H idden this 는 Heap 에 있는 Class 의 Instance 에 대한 reference 이다 .


Operand Stack

Operand Stack 은 JVM 의 작 업 공간이다 . 그 이유는 JVM 이 연산에 필요한 데이터와 연산 결 과를 Operand Stack 에 넣고 처리하기 때문이다 . 작동 방식은 하나의 Instruction 이 연산을 위 해 Operand Stack 에 값을 넣으면 다음 Instruction 에서는 이 값을 빼서 사용하게 된다 . 연산 의 결과 역시 Operand Stack 에 저장된다 . Operand Stack 역시 Array 로 구성되어 있으며 Stack 의 구조로 Push, Pop 작업을 수행한다 .


Frame Data

Stack Frame 을 구성하고 있는 영역이다 . 이 곳에서는 Constant Pool Resolution 정보와 Method 가 정상 종료 했을 때의 정보 또는 비정상 종료를 했을 때 발생하는 Exception 정보를 저장하고 있다 . Resolution 이란 Symbolic Reference 를 JVM 에서 실제 접근할 수 있는 Direct Reference 로 변경하는 것을 말한다 . Symbolic Reference 는 Method Area 의 Const ant Pool 에 저장된다 . Frame Data 에 저장된 Constant Pool Resolution 은 Method Area 의 Constant Pool 의 Pointer 이다 . JVM 은 필요할 때마다 Pointer 로 Constant Pool 에 접근한다 . 보통 상수 뿐만 아니라 다른 Class 를 참조하거나 , Method 를 접근할 경우에도 Constant Pool 을 참조해 야 한다 . 이는 Java 의 모든 Reference 과 Symbolic Reference 인 것과 관련이 있다 .

Method 가 수행이 되고 종료하는 시점에 Java Virtual Machine Stack 에서 해당 Stack Frame 이 Pop 되어 사라진다 . 이때 이전에 Method 를 찾아가야 하는데 Frame Data 에는 이전에 자신 을 호출한 Stack Frame 의 Instruction Pointer 가 들어가있다 . 만약 Method 가 exception 을 발생시키면 해당 exception 을 핸들링 해줘야 하는데 이 exception 정보가 Fram e Data 에 저장이 된다 .


Native Method Stacks

JVM 은 Native Method 를 위해 Native Method Stack 이라는 메모리 공간을 가진다 . Application 에서 Native Method 를 호출하게 되면 Native Method Stack 에 새로운 Stack Frame 을 생성하여 Push 한다 . 이는 JNI 를 이용해 JVM 내부에 영향을 주지 않기 위함이다 . Native Method 의 수행이 끝나면 해당 Method 를 호출한 Stack Frame 이 아닌 새로운 Stack Frame 을 하나 생성하여 작업을 수행한다 .



우리가 자주 사용하는 Hotspot JVM 이나 IBM JVM 에서는 두 Stack 영역을 구분 두지 않는다 . 모두 Native Stack 으로 통합이 되어 있는데 이는 JVM 에서 사용하는 Thread 가 Native Thread 인 것과 관계가 깊다 .

Hotspot JVM 에서 Stack Size 를 조정하는 옵션은 . Xss 와 . Xoss 두 가지 인데 , - Xss 는 Native Stack Size 를 조정하는 옵션이고 . Xoss 는 Stack Size 를 조정하는 옵션이다 . Hotspot JVM 에서 Stack Size 조정은 - Xss 만을 통해서 하도록 되어 있다 .


Method Area

Method Area 는 모든 Thread 가 공유하는 메모리 영역이다 . Method Area 는 Class 와 Interface 의 Bytecode 및 메타 데이터가 저장이 된다 . 이는 G abage Collection 의 대상이 되 며 Hotspot JVM 의 경우 Permenent Area 라는 명칭으로 사용된다 . IBM JVM 같은 경우는 Heap 내에 Class Object 형태로 저장된다 .


Constant Pool

Constant Pool 은 JVM 에서 가장 중요한 역할을 수행하는 곳이고 많이 사용되는 곳이기도 하다 . Constant Pool 에는 Literal Constant 는 물론이고 Filed(Member Variable, Class Va riable), Method 로의 모든 Symbolic Reference 까지 가진다 . Symbolic Reference 의 역할을 하는 곳 이 Constant Pool 이다 .


Field Information

Field Information 은 모든 Field 의 정보가 있다 .

. Field 이름
. Field 의 Data Type, 선언 순서
. p ublic, private 와 같은 Field 의 Modifier


Method Information

Method Informatio n 은 모든 Method 정보를 갖게 된다 .



. Method 이름 , Method 반환 값의 Data Type 과 void
. Method parameter 수와 Data Type, 선언 순서 , Method 의 Modifier


만약 Method 가 native 나 abstract 가 아니라면 다음의 정보가 추가된다 .



. Method 의 Bytecode
. Method Stack Frame 의 Operand Stack 및 Local Variable Section 의 크기
. Exception Table


Class Variable

Class Variable 은 static 으로 선언한 변수이며 Method Area 에 저장된다 . 이 변수는 모든 Instance 에서 접근 가능하기 때문에 동기화 이슈가 발생할 수 있다 . Class Variable 을 final 로 선언할 경우 이는 Constant Pool 에 Literal Constant 로 저장된다 .


Method Table

Method Area 에 저장되는 정보는 Heap 에 Object 를 생성할 때 사용되기 도 하나 Reference 를 위한 Data 로서의 역할도 중요하다 . Java 에서는 Reference 로 객체를 찾아 다니는 일은 속도 측면에서 굉장히 중요하다 . Method Table 은 Class 의 Method 에 대한 Direct Reference 를 가진다고 보면 된다 . Method Table 을 이용해 Super Class 에서 상속된 Method 의 Reference 까지 확인이 가능하다 .


Java Heap

Java Heap 에서 많은 성능 이슈가 발생하고 있 다 . Gabage Collection 에 의한 것이 대표적이 예이다 . Java Heap 은 Instance 와 Array 객체 두 종류가 저장되는 공간이다 . Java Heap 은 모 든 Thread 에 의해 공유된다고 했는데 그로 인해 동기화 문제가 발생할 수 있다 . Java Heap 은 Gabage Collection 이란 Mechanism 에 의해 메모리 해제 작업은 필요하지 않다 . 실제 많이 사 용하고 있는 Hotspot JVM 과 IBM JVM 의 Object 의 구조를 살펴보자 .


Object 구조

Heap 에 저장되는 Object 와 Array 객체는 Head 와 Data 로 나뉘게 된다 .


Hotspot Object 구조

Hotspot JVM 의 Object 의 경우 두 개의 Header 를 가지고 있고 , Array 객체의 경우 세 개의 Header 를 갖는다 .



First header 는 Mark Word 라 불리며 Gabage Collection 과 Syncronization 작업을 위해 사 용한다 . 두 번째 Header 에는 Method Area 의 Class 정보를 가리키는 Reference 정보가 저장 된다 . Array 의 경우 세 번째 Header 가 존재하게 되는데 Array Size 정보를 갖기 위한 공간

IBM JVM 은 Java 5 의 경우를 살펴보겠다 . Object 의 경우 2 개의 Header 를 가지고 Array 의 경우 Array Size 정보를 담고 있는 Header 를 포함해 총 3 개의 Header 를 가지게 된다 .



Vtable 은 Object Information 에 대한 Vtable Pointer 를 가지고 있고 이는 주로 Garbage Collector 에 의해 사용된다 . 두 번째 Header 는 Lock Word 를 이용해 Object 의 Lock 획득 유 무를 확인하기 위해 사용된다 .


Heap의 구조

Hotspot JVM Heap 구조

Hotspot Heap 의 가장 큰 특징은 Young Generat ion 과 Old Generation 으로 나뉘어 진다는 것이다 .



Young Generation 은 Eden 과 Survivor 영역으로 구성되어 있고 최초 Heap 에 객체가 할당되 는 곳은 Eden 이다 . 그 이후 Object 참조 여부를 확인해서 참조가 되어 있는 상태면 Survivor 영역으로 넘기고 오래 살아 남으면 Old 영역으로 이동시킨다 . 이를 Promotion 이라고 한다 . 참 고로 Young Gener ation 에서 일어나는 GC 를 Minor GC 라고 하고 Old Generation 에서 일어 나는 GC 를 Major GC 라고 한다 .


IBM JVM Heap 구조

IBM JVM Heap 은 버전에 따라 다른 모습을 보이고 있다 . 먼저 IBM JVM 1.4 를 살펴보도록 하 겠다 . 1.4 버전의 대표적 특징은 One - Heap 이라는 점이다 .



K Cluster 와 P Cluster 는 Hotspot JVM 의 Permanen t Area 와 같은 역할을 한다고 보면 된다 . K Cluster 가 Method Area 의 정보를 가지고 있는 Class Object 를 저장하는 공간인 반면 P Cluster 는 Pinned 상태의 Array 나 일반 Ojbect 를 저장한다 . Cache 영역은 Thread 마다 Lock 없이 할당할 수 있는 공간이다 . LOA 는 Large Object 를 위한 공간이다 . 이 Heap 은 Garbage Collection 과 객체에 빠른 할당을 하기 위해 Allocbit s 와 Markbits 라는 Bit Vector 와 Freelist 를 가진다 .



Allocbits 는 Object 의 시작점에 Bit 가 On 이 된다 . Allocbits 는 단순히 할당 여부만 알 수 있고 Garbage Collection 의 대상인지는 판단할 수 없다 . Object 의 Live 는 Markbits 를 통해 알 수 있다 . Cache Alloction 을 사용하여 Thread 가 Obj ect 를 할당할 경우는 Thread 에게 할당 된 Heap(TLH) 을 모두 사용한 후에나 Allocbits 에 On 으로 표시된다 . 그리고 Garbage Collection 에 의해 Free space 가 되면 다시 Off 로 된다 .

Freelist 는 Object 를 위해 Heap 공간을 할당 하기 위한 자료구조로 보면 된다 . 이 Freelist 는 linked List 구조로 되어 있으며 마지막 Chunk 의 Next Filed 는 Null 이다 . Object 에 Heap 을 할당하기 위해 Freelist 를 탐색 하고 맞는 Chunk 가 없으면 다음 Free Chunk 를 찾을 때까지 Jump 를 반복하게 된다 . 이때 사용하고 남은 Chunk 역시 Freelist 로 등록되고 만약 Chunk 의 Size 가 512 Byte 미만이면 이는 Compaction 의 대상이 된다 . 이렇게 작은 Free Chunk 를 Dark Matter 라고 한다 . 1.4 버전부터 sub pool 을 제공하는데 이는 Freelist 를 크기 별로 다양 하게 제공하는 장점 있다 . 기존 방법이 First Fit 이었다면 sub pool 방식은 Best Fit 을 추구한다 .


IBM JAVA 5 Heap 구조

JAVA 5 에서는 기존에 버전과 달리 두 가지 변화가 생긴다 . 하나는 System Heap 을 포함하지 않는 다는 것이고 다른 하나는 Hotspot JVM 과 같이 Generation Heap 을 사용할 수 있다는 것 이다 . 단 옵션을 적용할 때만 사용이 가능하다 . 옵션은 다음과 같다 .

-Xgcpolicy:gencon

Hots pot JVM 에서 Young Generation 은 Nursery Generation 이고 , Old Generation 은 Tenured Generation 이다



Nursery Area 는 Allocation Space 와 Survivor Space 로 나뉘게 되는데 , Allocation Space 는 Object 가 최초로 할당 되는 곳이고 Survivor Space 는 Allocation Space 가 가득 차거나 Allocation Failure 가 발생하면 이동되는 곳이다 . Tenured Space 는 Nersery Generation 의 성숙한 Object 들이 Promotion 하는 곳이다 .


결론

Runtime Data Areas 는 객체의 생성과 소멸이 반복되는 곳이다 . 그로 인해 성능 이슈가 빈번한 곳이기도 하다 . 지금껏 Runtime Data Areas 에 대해서 알아 보았는데 이는 성능 분석을 위한 기초가 될 것이라고 생각한다 . 앞 서 살펴보았듯이 하나를 참조를 위해 Java Stack, Method Area, Heap 의 전 부분에 Jump 작업을 수행한다는 것을 알고 있을 것이다 . 불필요한 Reference 의 남발은 성능을 떨어뜨리는 결과를 만든다 . 또한 불 필요하게 Method 의 Depth 역시 깊어지게 되어 Java Stack 에서는 Stack Frame 을 더 많이 생성해야 되고 그에 따라 push, pop 작업이 빈번해 진다 . 이렇게 Stack Frame 이 많아지는 것 역시 모두 Resour ce 낭비 로 이어 지게 된다 . 객체와 Primitive Type 차이가 좋은 예가 될 것이다 . 앞으로 Runtime Data Areas 지식을 바탕으로 공부해 나간다면 WAS 성능 전문가의 길도 그리 멀지만은 않을 것이다 .



출처 : (주)엑셈

제공 : DB포탈사이트 DBguide.net