SlideShare ist ein Scribd-Unternehmen logo
1 von 43
Downloaden Sie, um offline zu lesen
Greg’s Anatomy
JVM 메모리 해부학
오픈서베이 이동훈(a.k.a Greg)
greg.lee@opensurvey.co.kr
leewin12@gmail.com
최초작성: 2020-07-18
외부공개: 2020-09-23
배경
- 평화롭게 오픈서베이의 신규 데이터 분석 서비스인 OpenAnalytics 를
개발하던 어느날, QA 과정에서 OutOfMemory 이슈가 등장함.
- 이건 과거의 내가 미래의 나에게 뭔가 잘못한 것이 분명했음.
- 과거의 나를 회상해보는 시간을 잠시 가져봄.
- (과거의 나) 설문 응답 데이터가 커봐야 얼마나 크겠어
- 많아봐야 Long / String 이백만건 정도인데,
String은 별로 없으니, Long만 따졌을 때, 8 * 2_000_000 = 16 MB
많이 봐줘서 10배 쳐줘도 160 MB니 -Xmx6g (= Heap 6GB)면 메모린 남아돌겠지?
- 역시 과거의 나는 믿을게 별로 못 된다는 사실부터 재확인
Java Object
new Integer(1)
Q. JVM 상에서 위 Object의 크기는? (JVM 32 bit 가정)
A. 16 bytes(= 128 bits)
- 네, 그렇습니다. 16 byte * 8 = 128 bit
- 잠깐, 그런데, 실제 값은 고작 4 Byte고 나머진 뭔가요?
- 그리고 Retained Size와 Shallow Size는 또 뭔가요?
- Shallow Size는 객체 자체가 점유하고 있는 메모리 크기
- Retained Size는 직접 GC Root와 연결되지 않고, Shallow를 통해 간접 ref된 크기
코드로 추적해봅시다.
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public native int hashCode(); ← Retained Size (2)
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws
InterruptedException;
}
public final class Integer extends Number implements
Comparable<Integer> {
private final int value; ← Shallow Size (4)
}
public abstract class Number implements
java.io.Serializable {}
[주1] 코드 추적은 어디까지나 제 추측입니다. 틀린 부분 있으면 알려주세요
코드로 추적해봅시다.
/*
* jdk/src/share/native/java/lang/Object.c
*/
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode}, ← 2
{"wait", "(J)V", (void *)&JVM_MonitorWait}, ← 3
{"notify", "()V", (void *)&JVM_MonitorNotify}, ← 3
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll}, ← 3
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass
cls) {
(*env)->RegisterNatives(env, cls, methods,
sizeof(methods)/sizeof(methods[0]));
}
JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this) {
….
return (*env)->GetObjectClass(env, this); ← 1
}
이하 중략...
(결론적) Integer Object의 구성[1]
- 실제 primitive value 대비 Object의 크기 비율은 3:1 = 4배
0 32 64 96 128 160
(1) Class
Pointer
(2) Flags (3) Locks (5) size (4) int...
0 32 64 96 128
(1) Class
Pointer
(2) Flags (3) Locks (4) int
- Array, (5) size가 추가됨
- 실제 primitive value 대비 Object의 크기 비율은 4:1 = 5배 (최악 가정)
(1) Class pointer
- Class Type의 Memory Address
- 따라서, 당연히 JVM의 bit 버전에 영향을 받음.
- e.g. 윈도우 XP (x86)의 최대 인식 메모리는 최대 4G 였음
- (참고사항) JVM 64bit에 도입된 -XX:-UseCompressedOops -XX:-UseCompressedClassPointer 등에 영향 받음
- Oops: ordinary object pointer
- 오픈서베이 표준 JVM인 Zulu8은 기본적으로 두 옵션이 모두 true로 켜져있음
- Oracle JVM에서는 false로 꺼져있음
- 자세한 사항은 https://wiki.openjdk.java.net/display/HotSpot/CompressedOops
- A collection of flags that describe the state of the object,
including the hash code for the object if it has one, and the shape
of the object (that is, whether or not the object is an array) [1]
- 하지만 실제로, 코드상으로 확인되는 항목은 hashcode 뿐으로,
크기를 봤을 때 그 이상의 추가적인 flag가 존재하긴 어려워보임
- 뇌피셜입니다. (= 인터넷 문서상에서는 위처럼 기술되어 있지만, JDK 코드상에서 추가적
정보를 찾지 못함.)
(2) Flags
(3) Locks
- The synchronization information for the object — that is, whether
the object is currently synchronized [1]
- ()V로 표시되던, wait / notify 등 동기화 관련 상태 필드
(4) 타입별 크기 (Oracle JDK8 Spec, 32 bit)[2]
- Primitive 한 경우
- boolean 혼란[4]
- 첫 스펙 문서에서 크기를 정확히 지정하지 않았음.
- 4 bytes (Oracle JDK8 Spec: Where Java programming language boolean values are mapped by compilers to values
of Java Virtual Machine type int, the compilers must use the same encoding.) [2]
- 1 bytes (Zulu8)
- byte 1 byte
- char 2 bytes ← byte < char 크기차 주의, low-level 처리시 실수 포인트
- short 2 bytes
- int 4 bytes
- long 8 bytes
- float 4 bytes
- double 8 bytes
- Non-Primitive 한 경우
- Object 16 bytes
- String ? bytes
new String(6)
Q. JVM 상에서 위 Object의 크기는? (JVM 32 bit 가정)
A. 24 bytes + char array
0 32 64 96 128 160 192 224
(1) Class
Pointer
(2) Flags (3) Locks (4) char
Array
Pointer
(5) hash
(1) Class
Pointer
(2) Flags (3) Locks (4) size 1 / 2 3 / 4 5 / 6
- String은 내부에 다시 character array 와 hash로 구성
확인해봅시다 by JOLJava Object Layout [3]
$ java -jar jol-cli-0.11-full.jar internals java.lang.String
java.lang.String object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998)
12 4 char[] String.value []
16 4 int String.hash 0
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
얼추 맞아 보이죠?
그런데 말입니다…
코드로 추적해봅시다. Zulu8 (JDK8)
코드로 추적해봅시다. AdoptOpenJ9 (JDK8)
- int count가 있네요?
코드로 추적해봅시다. AdoptOpenJ9 (JDK11)
- char[] value → byte[] value
- byte count → byte coder ??
코드로 추적해봅시다. OpenJDK14 (JDK14)
- coder: encoding을 표현하는 필드
- int hashcode → int hash (아무리 Compile time에 이름을 제거한다지만, 이런걸 줄이냐...)
코드로 추적해봅시다. (결론)
- 디테일은 JDK Vender와 JDK Version에 의해 다르다.
(참고) String.intern
- String은 JVM에서 대우가 남다른 Type으로서, 별도의 저장영역 존재
- String.intern을 통해 JVM character pool에 Cache됨 (HashTable)
- String `==`와 `equals`에 주의해야하는 이유
Java Collection
Java Collection
- List
- ArrayList
- LinkedList
- Map
- HashMap
- LinkedHashMap
- TreeMap
- Set
- HashSet
- LinkedHashSet
- HashMap
ArrayList
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (5)
4 4 (object header) 00 00 00 00 (0)
8 4 (object header) 7e 2f 00 f8 (-134200)
12 4 int AbstractList.modCount 0
16 4 int ArrayList.size 0
20 4 java.lang.Object[] ArrayList.elementData []
Instance size: 24 bytes
LinkedList
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (5)
4 4 (object header) 00 00 00 00 (0)
8 4 (object header) 19 af 00 f8 (-134172903)
12 4 int AbstractList.modCount 0
16 4 int LinkedList.size 0
20 4 java.util.LinkedList.Node LinkedList.first null
24 4 java.util.LinkedList.Node LinkedList.last null
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
생각과 달리 크기가 작지 않습니다.
LinkedList
- LinkedList$Node
- Object item
- Node next
- Node prev
- Node first
- Node last
- int size
- Elements의 수에 비례해서 급격한 차이
- LinkedList 사용을 지양하고,
ArrayList.trimToSize() 사용권고
- new ArrayList()의 기본 크기 10이며,
크기를 초과할 경우, 임의의 크기 만큼
확장함
- 따라서, 실제 element 갯수보다 더 큰
크기를 확보하고 있을 가능성이 높음.
- trimToSize()는 이러한 Array 상의 null
element 제거해줌
그래프 출처: Numeron,
https://stackoverflow.com/a/7671021/1378965
ArrayList vs LinkedList
HashMap
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) (5)
4 4 (object header) (0)
8 4 (object header) (-134203459)
12 4 java.util.Set AbstractMap.keySet null
16 4 java.util.Collection AbstractMap.values null
20 4 int HashMap.size 0
24 4 int HashMap.modCount 0
28 4 int HashMap.threshold 0
32 4 float HashMap.loadFactor 0.75
36 4 java.util.HashMap.Node[] HashMap.table null
40 4 java.util.Set HashMap.entrySet null
44 4 (loss due to the next object alignment)
Instance size: 48 bytes
HashMap
- HashMap$Node
- int hash
- Object key
- Object value
- Node next
- Node[] table
- Set entrySet
- int size
- int modCount
- int threshold
- int loadFactor
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) (5)
4 4 (object header) (0)
8 4 (object header) (-134195647)
12 4 java.util.Set AbstractMap.keySet null
16 4 java.util.Collection AbstractMap.values null
24 4 int HashMap.modCount 0
20 4 int HashMap.size 0
28 4 int HashMap.threshold 0
32 4 float HashMap.loadFactor 0.75
36 4 java.util.HashMap.Node[] HashMap.table null
40 4 java.util.Set HashMap.entrySet null
44 1 boolean LinkedHashMap.accessOrder false
45 3 (alignment/padding gap)
48 4 java.util.LinkedHashMap.Entry LinkedHashMap.head null
52 4 java.util.LinkedHashMap.Entry LinkedHashMap.tail null
Instance size: 56 bytes
LinkedHashMap
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) (5)
4 4 (object header) (0)
8 4 (object header) (-134179429)
12 4 java.util.Set AbstractMap.keySet null
16 4 java.util.Collection AbstractMap.values null
20 4 int TreeMap.size 0
24 4 int TreeMap.modCount 0
28 4 java.util.Comparator TreeMap.comparator null
32 4 java.util.TreeMap.Entry TreeMap.root null
36 4 java.util.TreeMap.EntrySet TreeMap.entrySet null
40 4 java.util.TreeMap.KeySet TreeMap.navigableKeySet null
44 4 java.util.NavigableMap TreeMap.descendingMap null
Instance size: 48 bytes
TreeMap
Set
사실 Java의 Set은 Map으로 구현되어 있음
정말 Wrapper임 (= 직관적으로 기대되는 메모리 상 이득은 전혀 없음)
$ java -jar jol-cli-0.11-full.jar internals java.util.HashSet
java.util.HashSet object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) (5)
4 4 (object header) (0)
8 4 (object header) (-134177913)
12 4 java.util.HashMap HashSet.map (object)
Instance size: 16 bytes
개선해보기
개선해보기
- JVM의 Object는 생각보다 무겁다.
- 적절한 자료구조를 선택하기
- Queue가 필요한 것이 아닌 이상, LinkedList는 쓰지 말자.
- Set은 Map만큼 무겁다.
- 필요한 만큼만 사용하기
- ArrayList.trimToSize() : List 상의 null element 최소화
- new HashMap(7)
- JVM paramater 도입 -XX:+UseCompressOops
- Zulu8에선 이미 기본 적용사항임 https://chriswhocodes.com/zulu_jdk8_options.html
- 하지만, Oracle JDK8에서는 기본 값이 false임
- JVM parameter계의 explainshell 인 JaCoLine 도 겸사겸사 추천
개선해보기(cont.)
- Eclipse Collections
- Primitive Collection 구현체들 중 가장 잘 유지보수 되고 있는 오픈소스
- 메모리 최적화된 Set 구현체도 보유
- 하지만, 항상 그렇듯이 먼저 문서를 확인하시고, 프로젝트 별로 벤치마크를
권고드립니다. 요즘 JMH라는 좋은 툴이 생겼어요. (하지만 JDK8은 추가작업이…)
- 더 알아보기
- https://www.infoq.com/articles/eclipse-collections/
- https://www.infoq.com/articles/Refactoring-to-Eclipse-Collections/
개선해보기(cont.)
Eclipse Collections 도입 PoC 결과 비교(1)
- 믿기 어려울 정도의 개선효과
- 십수회 반복 측정 결과이지만, 그래도 뭔가 잘못 측정된 것이 아닐까?
구현방법 소요시간 Obj 갯수
최대 메모리 사용량
(Peak지점 사용량)
종료기점
Stron Reachable
Object 크기
JDK 기본 1,428,126 ms 224 M 6.4 Gb 3.6Gb
Eclipse Collections
503,218 ms
(65% 감소)
123 M
(45% 감소)
4.8 Gb
(25% 감소)
2.3 Gb
(34% 감소)
개선해보기(cont.)
메모리 상 Object 구성 분석 thanks to yourkit
- (상) JDK 기본
- (하) EclipseCollections
Eclipse Collections 도입 PoC 결과 비교 (2)
개선해보기(cont.)
● 메모리 상 Object 구성(2)이 크게 달라진 것을 확인 할 수 있음
○ EC.Immutable*List의 특징
■ List가 Imuutable 하다는 점을 이용하여 다양한 최적화가 적용되어있음
■ List 크기 불변성을 이용한 null element 수 최소화
■ ImmutableSingleList부터 Decapleton까지 element 갯수에 따른 micro tuning
● Immutable 자료구조를 통해 기존 Defensive Copy 정책으로 인한 중복 Object 생성비용 절감
● 메모리 상 Object 구성(2)에서 Object[]로 표현되던, 각종 자료 구조(ArrayList, Set)
내부에서 참조 중인 Object를 Primitive로 다이어트
● (퍼포먼스 상 부가이득) Boxing / Unboxing 비용절약
● (퍼포먼스 상 부가이득) 효율적인 메모리 활용을 통한 GC 소요시간 단축
결론: OpenAnalytics의 구조적 특징과 Primitive 자료구조의 시너지 효과
Eclipse Collections 도입 PoC 결과 비교 (3)
Q. 그렇다면 다른 프로젝트에서도 이런 드라마틱한 효과를 기대할 수 있을까요?
A. 그럴 수도 있고 아닐 수도 있습니다. 전술한 바와같이, OpenAnalytics의 드라마틱한 개선효과는
전적으로 OpenAnalytics의 구조적 특징과 Primitive 자료구조의 시너지 효과입니다.
본 자료는 Eclipse Collections 도입시, 성능 향상 가능성을 판단하는데,
도움을 줄 수 있는 사례 하나라고 생각합니다.
도입에 앞서서 충분한 검토와 Benchmark를 권고합니다.
개선해보기(cont.)
Eclipse Collections 도입 PoC 결과 비교 (4)
[없을 수도 있는 차회예고]
VTL: 오픈서베이에서 개발한 설문분석 전용 DSL 개발기
Shell pipe 스타일의 집합 연산 언어
끝!
참고문헌
[1] https://www.ibm.com/developerworks/java/library/j-codetoheap/index.html
[2] https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.3
[3] https://openjdk.java.net/projects/code-tools/jol/
[4] https://stackoverflow.com/questions/383551/what-is-the-size-of-a-boolean-variable-in-java
부록: JOL
JOL-cli https://repo.maven.apache.org/maven2/org/openjdk/jol/jol-cli/0.11/jol-cli-0.11-full.jar
$ java -jar jol-cli-0.11-full.jar
Usage: jol-cli.jar <mode> [optional arguments]*
Available modes:
estimates: Simulate the class layout in different VM modes.
externals: Show the object externals: the objects reachable from a given instance.
footprint: Estimate the footprint of all objects reachable from a given instance
heapdump: Consume the heap dump and estimate the savings in different layout strategies.
heapdumpstats: Consume the heap dump and print the most frequent instances.
idealpack: Compute the object footprint under different field layout strategies.
internals: Show the object internals: field layout and default contents, object header
shapes: Dump the object shapes present in JAR files or heap dumps.
string-compress: Consume the heap dumps and figures out the savings attainable with compressed strings.
적용해보기: http://www.mastertheboss.com/jboss-server/jboss-monitoring/monitoring-the-size-of-your-java-objects-with-java-object-layout
com.idincu.analytics2.ast.value.ValueRow object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) (13)
4 4 (object header) (0)
8 4 (object header) (-133007067)
12 4 java.util.Set AbstractMap.keySet null
16 4 java.util.Collection AbstractMap.values null
20 4 int HashMap.size 48
24 4 int HashMap.modCount 48
28 4 int HashMap.threshold 48
32 4 float HashMap.loadFactor 0.75
36 4 java.util.HashMap.Node[] HashMap.table [(object), null, ... ]
40 4 java.util.Set HashMap.entrySet null
44 4 (loss due to the next object alignment)
Instance size: 48 bytes
부록: JOL

Weitere ähnliche Inhalte

Was ist angesagt?

AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...
AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...
AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...Amazon Web Services LATAM
 
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開 第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開 Keisuke Matsuda
 
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #1320210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13Amazon Web Services Japan
 
Rails の自動読み込みを支える技術
Rails の自動読み込みを支える技術Rails の自動読み込みを支える技術
Rails の自動読み込みを支える技術Tomohiko Himura
 
SPAのルーティングの話
SPAのルーティングの話SPAのルーティングの話
SPAのルーティングの話ushiboy
 
サーバーレスで ガチ本番運用までやってるお話し
サーバーレスで ガチ本番運用までやってるお話しサーバーレスで ガチ本番運用までやってるお話し
サーバーレスで ガチ本番運用までやってるお話しAkira Nagata
 
マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜Yoshiki Nakagawa
 
FINAL FANTASY Record Keeperを支えたGolang
FINAL FANTASY Record Keeperを支えたGolangFINAL FANTASY Record Keeperを支えたGolang
FINAL FANTASY Record Keeperを支えたGolangYoshiki Shibukawa
 
マイクロサービスにおける 結果整合性との戦い
マイクロサービスにおける 結果整合性との戦いマイクロサービスにおける 結果整合性との戦い
マイクロサービスにおける 結果整合性との戦いota42y
 
本当にあったRailsの怖い話
本当にあったRailsの怖い話本当にあったRailsの怖い話
本当にあったRailsの怖い話Yuto Komai
 
Goの時刻に関するテスト
Goの時刻に関するテストGoの時刻に関するテスト
Goの時刻に関するテストKentaro Kawano
 
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...Google Cloud Platform - Japan
 
Monitoring - 入門監視
Monitoring - 入門監視Monitoring - 入門監視
Monitoring - 入門監視Eiji KOMINAMI
 
カジュアルにVPC作った結果がこれだよ!
カジュアルにVPC作った結果がこれだよ!カジュアルにVPC作った結果がこれだよ!
カジュアルにVPC作った結果がこれだよ!Emma Haruka Iwao
 
Demystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes ServiceDemystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes ServiceToru Makabe
 
모션 매칭이란 무엇인가.pptx
모션 매칭이란 무엇인가.pptx모션 매칭이란 무엇인가.pptx
모션 매칭이란 무엇인가.pptxsung suk seo
 
[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)
[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)
[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)Hyojun Jeon
 
AWS Black Belt Techシリーズ Amazon CloudSearch
AWS Black Belt Techシリーズ Amazon CloudSearchAWS Black Belt Techシリーズ Amazon CloudSearch
AWS Black Belt Techシリーズ Amazon CloudSearchAmazon Web Services Japan
 

Was ist angesagt? (20)

AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...
AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...
AWS Webinar Series Brasil: Como sair de seu datacenter e modernizar cargas de...
 
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開 第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
 
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #1320210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
 
Rails の自動読み込みを支える技術
Rails の自動読み込みを支える技術Rails の自動読み込みを支える技術
Rails の自動読み込みを支える技術
 
SPAのルーティングの話
SPAのルーティングの話SPAのルーティングの話
SPAのルーティングの話
 
サーバーレスで ガチ本番運用までやってるお話し
サーバーレスで ガチ本番運用までやってるお話しサーバーレスで ガチ本番運用までやってるお話し
サーバーレスで ガチ本番運用までやってるお話し
 
マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜
 
FINAL FANTASY Record Keeperを支えたGolang
FINAL FANTASY Record Keeperを支えたGolangFINAL FANTASY Record Keeperを支えたGolang
FINAL FANTASY Record Keeperを支えたGolang
 
マイクロサービスにおける 結果整合性との戦い
マイクロサービスにおける 結果整合性との戦いマイクロサービスにおける 結果整合性との戦い
マイクロサービスにおける 結果整合性との戦い
 
本当にあったRailsの怖い話
本当にあったRailsの怖い話本当にあったRailsの怖い話
本当にあったRailsの怖い話
 
Goの時刻に関するテスト
Goの時刻に関するテストGoの時刻に関するテスト
Goの時刻に関するテスト
 
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
 
Monitoring - 入門監視
Monitoring - 入門監視Monitoring - 入門監視
Monitoring - 入門監視
 
カジュアルにVPC作った結果がこれだよ!
カジュアルにVPC作った結果がこれだよ!カジュアルにVPC作った結果がこれだよ!
カジュアルにVPC作った結果がこれだよ!
 
Demystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes ServiceDemystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes Service
 
모션 매칭이란 무엇인가.pptx
모션 매칭이란 무엇인가.pptx모션 매칭이란 무엇인가.pptx
모션 매칭이란 무엇인가.pptx
 
DevOps with Database on AWS
DevOps with Database on AWSDevOps with Database on AWS
DevOps with Database on AWS
 
Google Cloud で実践する SRE
Google Cloud で実践する SRE  Google Cloud で実践する SRE
Google Cloud で実践する SRE
 
[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)
[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)
[NDC18] 야생의 땅 듀랑고의 데이터 엔지니어링 이야기: 로그 시스템 구축 경험 공유 (2부)
 
AWS Black Belt Techシリーズ Amazon CloudSearch
AWS Black Belt Techシリーズ Amazon CloudSearchAWS Black Belt Techシリーズ Amazon CloudSearch
AWS Black Belt Techシリーズ Amazon CloudSearch
 

Ähnlich wie JVM 메모리 해부학

Scala, Scalability
Scala, ScalabilityScala, Scalability
Scala, ScalabilityDongwook Lee
 
Collection framework
Collection frameworkCollection framework
Collection frameworkssuser34b989
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)MIN SEOK KOO
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10hungrok
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8Sangmin Lee
 
Programming java day2
Programming java day2Programming java day2
Programming java day2Jaehoonyam
 
자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라Jong Gook Bae
 
Java mentoring of samsung scsc 2
Java mentoring of samsung scsc   2Java mentoring of samsung scsc   2
Java mentoring of samsung scsc 2도현 김
 
From Java code to Java heap_SYS4U I&C
From Java code to Java heap_SYS4U I&CFrom Java code to Java heap_SYS4U I&C
From Java code to Java heap_SYS4U I&Csys4u
 
XECon + PHPFest 2014 Keynote
XECon + PHPFest 2014 KeynoteXECon + PHPFest 2014 Keynote
XECon + PHPFest 2014 KeynoteSol Kim
 
자바로 배우는 자료구조
자바로 배우는 자료구조자바로 배우는 자료구조
자바로 배우는 자료구조중선 곽
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!WooYoung Cho
 
Java 변수자료형
Java 변수자료형Java 변수자료형
Java 변수자료형Hyosang Hong
 
Java_02 변수자료형
Java_02 변수자료형Java_02 변수자료형
Java_02 변수자료형Hong Hyo Sang
 

Ähnlich wie JVM 메모리 해부학 (20)

Scala, Scalability
Scala, ScalabilityScala, Scalability
Scala, Scalability
 
Scalability
ScalabilityScalability
Scalability
 
Collection framework
Collection frameworkCollection framework
Collection framework
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
Programming java day2
Programming java day2Programming java day2
Programming java day2
 
Gpg1
Gpg1Gpg1
Gpg1
 
자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라
 
Java mentoring of samsung scsc 2
Java mentoring of samsung scsc   2Java mentoring of samsung scsc   2
Java mentoring of samsung scsc 2
 
From Java code to Java heap_SYS4U I&C
From Java code to Java heap_SYS4U I&CFrom Java code to Java heap_SYS4U I&C
From Java code to Java heap_SYS4U I&C
 
XECon + PHPFest 2014 Keynote
XECon + PHPFest 2014 KeynoteXECon + PHPFest 2014 Keynote
XECon + PHPFest 2014 Keynote
 
ES6 for Node.js Study 4주차
ES6 for Node.js Study 4주차ES6 for Node.js Study 4주차
ES6 for Node.js Study 4주차
 
자바로 배우는 자료구조
자바로 배우는 자료구조자바로 배우는 자료구조
자바로 배우는 자료구조
 
4-1. javascript
4-1. javascript4-1. javascript
4-1. javascript
 
Scala
ScalaScala
Scala
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!
 
Java 변수자료형
Java 변수자료형Java 변수자료형
Java 변수자료형
 
Java_02 변수자료형
Java_02 변수자료형Java_02 변수자료형
Java_02 변수자료형
 
JDK 변천사
JDK 변천사JDK 변천사
JDK 변천사
 

JVM 메모리 해부학

  • 1. Greg’s Anatomy JVM 메모리 해부학 오픈서베이 이동훈(a.k.a Greg) greg.lee@opensurvey.co.kr leewin12@gmail.com 최초작성: 2020-07-18 외부공개: 2020-09-23
  • 2. 배경 - 평화롭게 오픈서베이의 신규 데이터 분석 서비스인 OpenAnalytics 를 개발하던 어느날, QA 과정에서 OutOfMemory 이슈가 등장함. - 이건 과거의 내가 미래의 나에게 뭔가 잘못한 것이 분명했음. - 과거의 나를 회상해보는 시간을 잠시 가져봄. - (과거의 나) 설문 응답 데이터가 커봐야 얼마나 크겠어 - 많아봐야 Long / String 이백만건 정도인데, String은 별로 없으니, Long만 따졌을 때, 8 * 2_000_000 = 16 MB 많이 봐줘서 10배 쳐줘도 160 MB니 -Xmx6g (= Heap 6GB)면 메모린 남아돌겠지? - 역시 과거의 나는 믿을게 별로 못 된다는 사실부터 재확인
  • 4. new Integer(1) Q. JVM 상에서 위 Object의 크기는? (JVM 32 bit 가정)
  • 5. A. 16 bytes(= 128 bits) - 네, 그렇습니다. 16 byte * 8 = 128 bit - 잠깐, 그런데, 실제 값은 고작 4 Byte고 나머진 뭔가요? - 그리고 Retained Size와 Shallow Size는 또 뭔가요? - Shallow Size는 객체 자체가 점유하고 있는 메모리 크기 - Retained Size는 직접 GC Root와 연결되지 않고, Shallow를 통해 간접 ref된 크기
  • 6. 코드로 추적해봅시다. public class Object { private static native void registerNatives(); static { registerNatives(); } public native int hashCode(); ← Retained Size (2) public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; } public final class Integer extends Number implements Comparable<Integer> { private final int value; ← Shallow Size (4) } public abstract class Number implements java.io.Serializable {} [주1] 코드 추적은 어디까지나 제 추측입니다. 틀린 부분 있으면 알려주세요
  • 7. 코드로 추적해봅시다. /* * jdk/src/share/native/java/lang/Object.c */ static JNINativeMethod methods[] = { {"hashCode", "()I", (void *)&JVM_IHashCode}, ← 2 {"wait", "(J)V", (void *)&JVM_MonitorWait}, ← 3 {"notify", "()V", (void *)&JVM_MonitorNotify}, ← 3 {"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll}, ← 3 {"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone}, Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) { (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])); } JNIEXPORT jclass JNICALL Java_java_lang_Object_getClass(JNIEnv *env, jobject this) { …. return (*env)->GetObjectClass(env, this); ← 1 } 이하 중략...
  • 8. (결론적) Integer Object의 구성[1] - 실제 primitive value 대비 Object의 크기 비율은 3:1 = 4배 0 32 64 96 128 160 (1) Class Pointer (2) Flags (3) Locks (5) size (4) int... 0 32 64 96 128 (1) Class Pointer (2) Flags (3) Locks (4) int - Array, (5) size가 추가됨 - 실제 primitive value 대비 Object의 크기 비율은 4:1 = 5배 (최악 가정)
  • 9. (1) Class pointer - Class Type의 Memory Address - 따라서, 당연히 JVM의 bit 버전에 영향을 받음. - e.g. 윈도우 XP (x86)의 최대 인식 메모리는 최대 4G 였음 - (참고사항) JVM 64bit에 도입된 -XX:-UseCompressedOops -XX:-UseCompressedClassPointer 등에 영향 받음 - Oops: ordinary object pointer - 오픈서베이 표준 JVM인 Zulu8은 기본적으로 두 옵션이 모두 true로 켜져있음 - Oracle JVM에서는 false로 꺼져있음 - 자세한 사항은 https://wiki.openjdk.java.net/display/HotSpot/CompressedOops
  • 10. - A collection of flags that describe the state of the object, including the hash code for the object if it has one, and the shape of the object (that is, whether or not the object is an array) [1] - 하지만 실제로, 코드상으로 확인되는 항목은 hashcode 뿐으로, 크기를 봤을 때 그 이상의 추가적인 flag가 존재하긴 어려워보임 - 뇌피셜입니다. (= 인터넷 문서상에서는 위처럼 기술되어 있지만, JDK 코드상에서 추가적 정보를 찾지 못함.) (2) Flags
  • 11. (3) Locks - The synchronization information for the object — that is, whether the object is currently synchronized [1] - ()V로 표시되던, wait / notify 등 동기화 관련 상태 필드
  • 12. (4) 타입별 크기 (Oracle JDK8 Spec, 32 bit)[2] - Primitive 한 경우 - boolean 혼란[4] - 첫 스펙 문서에서 크기를 정확히 지정하지 않았음. - 4 bytes (Oracle JDK8 Spec: Where Java programming language boolean values are mapped by compilers to values of Java Virtual Machine type int, the compilers must use the same encoding.) [2] - 1 bytes (Zulu8) - byte 1 byte - char 2 bytes ← byte < char 크기차 주의, low-level 처리시 실수 포인트 - short 2 bytes - int 4 bytes - long 8 bytes - float 4 bytes - double 8 bytes - Non-Primitive 한 경우 - Object 16 bytes - String ? bytes
  • 13. new String(6) Q. JVM 상에서 위 Object의 크기는? (JVM 32 bit 가정)
  • 14. A. 24 bytes + char array 0 32 64 96 128 160 192 224 (1) Class Pointer (2) Flags (3) Locks (4) char Array Pointer (5) hash (1) Class Pointer (2) Flags (3) Locks (4) size 1 / 2 3 / 4 5 / 6 - String은 내부에 다시 character array 와 hash로 구성
  • 15. 확인해봅시다 by JOLJava Object Layout [3] $ java -jar jol-cli-0.11-full.jar internals java.lang.String java.lang.String object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998) 12 4 char[] String.value [] 16 4 int String.hash 0 Instance size: 24 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total 얼추 맞아 보이죠? 그런데 말입니다…
  • 17. 코드로 추적해봅시다. AdoptOpenJ9 (JDK8) - int count가 있네요?
  • 18. 코드로 추적해봅시다. AdoptOpenJ9 (JDK11) - char[] value → byte[] value - byte count → byte coder ??
  • 19. 코드로 추적해봅시다. OpenJDK14 (JDK14) - coder: encoding을 표현하는 필드 - int hashcode → int hash (아무리 Compile time에 이름을 제거한다지만, 이런걸 줄이냐...)
  • 20. 코드로 추적해봅시다. (결론) - 디테일은 JDK Vender와 JDK Version에 의해 다르다.
  • 21. (참고) String.intern - String은 JVM에서 대우가 남다른 Type으로서, 별도의 저장영역 존재 - String.intern을 통해 JVM character pool에 Cache됨 (HashTable) - String `==`와 `equals`에 주의해야하는 이유
  • 23. Java Collection - List - ArrayList - LinkedList - Map - HashMap - LinkedHashMap - TreeMap - Set - HashSet - LinkedHashSet - HashMap
  • 24. ArrayList OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (5) 4 4 (object header) 00 00 00 00 (0) 8 4 (object header) 7e 2f 00 f8 (-134200) 12 4 int AbstractList.modCount 0 16 4 int ArrayList.size 0 20 4 java.lang.Object[] ArrayList.elementData [] Instance size: 24 bytes
  • 25. LinkedList OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (5) 4 4 (object header) 00 00 00 00 (0) 8 4 (object header) 19 af 00 f8 (-134172903) 12 4 int AbstractList.modCount 0 16 4 int LinkedList.size 0 20 4 java.util.LinkedList.Node LinkedList.first null 24 4 java.util.LinkedList.Node LinkedList.last null 28 4 (loss due to the next object alignment) Instance size: 32 bytes 생각과 달리 크기가 작지 않습니다.
  • 26. LinkedList - LinkedList$Node - Object item - Node next - Node prev - Node first - Node last - int size
  • 27. - Elements의 수에 비례해서 급격한 차이 - LinkedList 사용을 지양하고, ArrayList.trimToSize() 사용권고 - new ArrayList()의 기본 크기 10이며, 크기를 초과할 경우, 임의의 크기 만큼 확장함 - 따라서, 실제 element 갯수보다 더 큰 크기를 확보하고 있을 가능성이 높음. - trimToSize()는 이러한 Array 상의 null element 제거해줌 그래프 출처: Numeron, https://stackoverflow.com/a/7671021/1378965 ArrayList vs LinkedList
  • 28. HashMap OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) (5) 4 4 (object header) (0) 8 4 (object header) (-134203459) 12 4 java.util.Set AbstractMap.keySet null 16 4 java.util.Collection AbstractMap.values null 20 4 int HashMap.size 0 24 4 int HashMap.modCount 0 28 4 int HashMap.threshold 0 32 4 float HashMap.loadFactor 0.75 36 4 java.util.HashMap.Node[] HashMap.table null 40 4 java.util.Set HashMap.entrySet null 44 4 (loss due to the next object alignment) Instance size: 48 bytes
  • 29. HashMap - HashMap$Node - int hash - Object key - Object value - Node next - Node[] table - Set entrySet - int size - int modCount - int threshold - int loadFactor
  • 30. OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) (5) 4 4 (object header) (0) 8 4 (object header) (-134195647) 12 4 java.util.Set AbstractMap.keySet null 16 4 java.util.Collection AbstractMap.values null 24 4 int HashMap.modCount 0 20 4 int HashMap.size 0 28 4 int HashMap.threshold 0 32 4 float HashMap.loadFactor 0.75 36 4 java.util.HashMap.Node[] HashMap.table null 40 4 java.util.Set HashMap.entrySet null 44 1 boolean LinkedHashMap.accessOrder false 45 3 (alignment/padding gap) 48 4 java.util.LinkedHashMap.Entry LinkedHashMap.head null 52 4 java.util.LinkedHashMap.Entry LinkedHashMap.tail null Instance size: 56 bytes LinkedHashMap
  • 31. OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) (5) 4 4 (object header) (0) 8 4 (object header) (-134179429) 12 4 java.util.Set AbstractMap.keySet null 16 4 java.util.Collection AbstractMap.values null 20 4 int TreeMap.size 0 24 4 int TreeMap.modCount 0 28 4 java.util.Comparator TreeMap.comparator null 32 4 java.util.TreeMap.Entry TreeMap.root null 36 4 java.util.TreeMap.EntrySet TreeMap.entrySet null 40 4 java.util.TreeMap.KeySet TreeMap.navigableKeySet null 44 4 java.util.NavigableMap TreeMap.descendingMap null Instance size: 48 bytes TreeMap
  • 32. Set 사실 Java의 Set은 Map으로 구현되어 있음 정말 Wrapper임 (= 직관적으로 기대되는 메모리 상 이득은 전혀 없음) $ java -jar jol-cli-0.11-full.jar internals java.util.HashSet java.util.HashSet object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) (5) 4 4 (object header) (0) 8 4 (object header) (-134177913) 12 4 java.util.HashMap HashSet.map (object) Instance size: 16 bytes
  • 34. 개선해보기 - JVM의 Object는 생각보다 무겁다. - 적절한 자료구조를 선택하기 - Queue가 필요한 것이 아닌 이상, LinkedList는 쓰지 말자. - Set은 Map만큼 무겁다. - 필요한 만큼만 사용하기 - ArrayList.trimToSize() : List 상의 null element 최소화 - new HashMap(7) - JVM paramater 도입 -XX:+UseCompressOops - Zulu8에선 이미 기본 적용사항임 https://chriswhocodes.com/zulu_jdk8_options.html - 하지만, Oracle JDK8에서는 기본 값이 false임 - JVM parameter계의 explainshell 인 JaCoLine 도 겸사겸사 추천
  • 35. 개선해보기(cont.) - Eclipse Collections - Primitive Collection 구현체들 중 가장 잘 유지보수 되고 있는 오픈소스 - 메모리 최적화된 Set 구현체도 보유 - 하지만, 항상 그렇듯이 먼저 문서를 확인하시고, 프로젝트 별로 벤치마크를 권고드립니다. 요즘 JMH라는 좋은 툴이 생겼어요. (하지만 JDK8은 추가작업이…) - 더 알아보기 - https://www.infoq.com/articles/eclipse-collections/ - https://www.infoq.com/articles/Refactoring-to-Eclipse-Collections/
  • 36. 개선해보기(cont.) Eclipse Collections 도입 PoC 결과 비교(1) - 믿기 어려울 정도의 개선효과 - 십수회 반복 측정 결과이지만, 그래도 뭔가 잘못 측정된 것이 아닐까? 구현방법 소요시간 Obj 갯수 최대 메모리 사용량 (Peak지점 사용량) 종료기점 Stron Reachable Object 크기 JDK 기본 1,428,126 ms 224 M 6.4 Gb 3.6Gb Eclipse Collections 503,218 ms (65% 감소) 123 M (45% 감소) 4.8 Gb (25% 감소) 2.3 Gb (34% 감소)
  • 37. 개선해보기(cont.) 메모리 상 Object 구성 분석 thanks to yourkit - (상) JDK 기본 - (하) EclipseCollections Eclipse Collections 도입 PoC 결과 비교 (2)
  • 38. 개선해보기(cont.) ● 메모리 상 Object 구성(2)이 크게 달라진 것을 확인 할 수 있음 ○ EC.Immutable*List의 특징 ■ List가 Imuutable 하다는 점을 이용하여 다양한 최적화가 적용되어있음 ■ List 크기 불변성을 이용한 null element 수 최소화 ■ ImmutableSingleList부터 Decapleton까지 element 갯수에 따른 micro tuning ● Immutable 자료구조를 통해 기존 Defensive Copy 정책으로 인한 중복 Object 생성비용 절감 ● 메모리 상 Object 구성(2)에서 Object[]로 표현되던, 각종 자료 구조(ArrayList, Set) 내부에서 참조 중인 Object를 Primitive로 다이어트 ● (퍼포먼스 상 부가이득) Boxing / Unboxing 비용절약 ● (퍼포먼스 상 부가이득) 효율적인 메모리 활용을 통한 GC 소요시간 단축 결론: OpenAnalytics의 구조적 특징과 Primitive 자료구조의 시너지 효과 Eclipse Collections 도입 PoC 결과 비교 (3)
  • 39. Q. 그렇다면 다른 프로젝트에서도 이런 드라마틱한 효과를 기대할 수 있을까요? A. 그럴 수도 있고 아닐 수도 있습니다. 전술한 바와같이, OpenAnalytics의 드라마틱한 개선효과는 전적으로 OpenAnalytics의 구조적 특징과 Primitive 자료구조의 시너지 효과입니다. 본 자료는 Eclipse Collections 도입시, 성능 향상 가능성을 판단하는데, 도움을 줄 수 있는 사례 하나라고 생각합니다. 도입에 앞서서 충분한 검토와 Benchmark를 권고합니다. 개선해보기(cont.) Eclipse Collections 도입 PoC 결과 비교 (4)
  • 40. [없을 수도 있는 차회예고] VTL: 오픈서베이에서 개발한 설문분석 전용 DSL 개발기 Shell pipe 스타일의 집합 연산 언어 끝!
  • 41. 참고문헌 [1] https://www.ibm.com/developerworks/java/library/j-codetoheap/index.html [2] https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.3 [3] https://openjdk.java.net/projects/code-tools/jol/ [4] https://stackoverflow.com/questions/383551/what-is-the-size-of-a-boolean-variable-in-java
  • 42. 부록: JOL JOL-cli https://repo.maven.apache.org/maven2/org/openjdk/jol/jol-cli/0.11/jol-cli-0.11-full.jar $ java -jar jol-cli-0.11-full.jar Usage: jol-cli.jar <mode> [optional arguments]* Available modes: estimates: Simulate the class layout in different VM modes. externals: Show the object externals: the objects reachable from a given instance. footprint: Estimate the footprint of all objects reachable from a given instance heapdump: Consume the heap dump and estimate the savings in different layout strategies. heapdumpstats: Consume the heap dump and print the most frequent instances. idealpack: Compute the object footprint under different field layout strategies. internals: Show the object internals: field layout and default contents, object header shapes: Dump the object shapes present in JAR files or heap dumps. string-compress: Consume the heap dumps and figures out the savings attainable with compressed strings.
  • 43. 적용해보기: http://www.mastertheboss.com/jboss-server/jboss-monitoring/monitoring-the-size-of-your-java-objects-with-java-object-layout com.idincu.analytics2.ast.value.ValueRow object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) (13) 4 4 (object header) (0) 8 4 (object header) (-133007067) 12 4 java.util.Set AbstractMap.keySet null 16 4 java.util.Collection AbstractMap.values null 20 4 int HashMap.size 48 24 4 int HashMap.modCount 48 28 4 int HashMap.threshold 48 32 4 float HashMap.loadFactor 0.75 36 4 java.util.HashMap.Node[] HashMap.table [(object), null, ... ] 40 4 java.util.Set HashMap.entrySet null 44 4 (loss due to the next object alignment) Instance size: 48 bytes 부록: JOL