jol(Java Object Layout)を使ったオブジェクトのサイズ取得
jol(Java Object Layout)というOpenJDKに含まれるツールを使用して、オブジェクトのメモリサイズが取得できるらしいので試してみる。
■環境
・Windows7 Home Premium 64bit
・JDK 1.8.0_60-b27
・Eclipse Luna SR1 (4.4.1)
・jol (0.4) (※jol-cli-0.4-full.jar)
■すること
jolを使用して何ができるのかを調べる。
主目的は、1処理におけるメモリ量の取得とする。
よって割とメイン所(と思われる)の機能のみ追いかける。
■クラス紹介
1.ClassLayoutクラス
jolを使用する上で基本となるクラス。クラス・クラスインスタンスのメモリ情報を取り扱う。
●処理対象特定系
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | ○ | ClassLayout | parseInstance | Object | インスタンスのメモリ情報を取得する。 |
2 | ○ | ClassLayout | parseInstance | Object, Layouter | インスタンスのメモリ情報を取得する。第二引数のLayouterで読み込み時の動作変更が可能 |
3 | ○ | ClassLayout | parseClass | Object | クラスのメモリ情報を取得する。 |
4 | ○ | ClassLayout | parseClass | Object, Layouter | クラスのメモリ情報を取得する。第二引数のLayouterで読み込み時の動作変更が可能 |
●サイズ取得系
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
5 | SortedSet< FieldLayout> | fields | - | インスタンス内に含まれるフィールドのメモリ情報を取得する。 | |
6 | int | headerSize | - | インスタンスのヘッダサイズ(int値)を取得する。 | |
7 | int | instanceSize | - | インスタンスのサイズ(int値)を取得する。 | |
8 | String | toPrintable | - | インスタンスのメモリ情報を整形して詳細情報を出力する。 | |
9 | String | toString | - | インスタンスのメモリ情報を整形して出力する。 |
2.FieldLayoutクラス
フィールドのメモリ情報を取り扱う。
●サイズ取得系
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | String | name | - | フィールド名を取得する。 | |
2 | String | offset | - | インスタンスが占めるサイズの先頭からのメモリ量を取得する。 | |
3 | int | size | - | フィールドのサイズを取得する。 | |
4 | String | typeClass | - | フィールドの型を取得する。 | |
5 | String | toString | - | フィールドの詳細を取得する。 |
3.VMSupportクラス
JVMのメモリに関連する情報を取得する。
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | ○ | String | vmDetails | - | JVMのメモリ情報を出力する。 |
4.GraphLayoutクラス
インスタンス生成からGraphLayout#parseInstanceした時点までにおける、指定したインスタンスに対するメモリの状態を可視化する。
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | ○ | GraphLayout | parseInstance | Object | インスタンスのメモリ情報を取得する。 |
2 | ○ | - | toImage | String | 引数で指定したファイル名(~.png等)でグラフを生成する。 |
●HelloWorld的なやつ
package com.hhhhhskw.jol; import java.util.SortedSet; import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.info.FieldLayout; import org.openjdk.jol.util.VMSupport; public class HelloJol { private String HELLO_JOL_HOGE = "HOGEEEEEEEEEEEEEEEEE"; private String HELLO_JOL_FUGA = "FUGAAAAAAAAAAAAAAAAA"; public static void main(String[] args) { HelloJol hj = new HelloJol(); System.out.println("■JVM情報■"); System.out.println(VMSupport.vmDetails()); System.out.println("■クラスインスタンスのメモリ情報■"); System.out.println(ClassLayout.parseInstance(hj).instanceSize()); System.out.println(ClassLayout.parseInstance(hj)); System.out.println(ClassLayout.parseInstance(hj).toPrintable()); SortedSet<FieldLayout> flSet = ClassLayout.parseInstance(hj).fields(); flSet.stream().forEachOrdered(fl -> { System.out.println("■フィールドのメモリ情報■"); System.out.println(fl.name()); System.out.println(fl.size()); System.out.println(fl.typeClass()); System.out.println(fl); }); System.out.println(flSet); } }
●実行結果*1
■JVM情報■ WARNING: Unable to attach Serviceability Agent. You can try again with super-user privileges. Use -Djol.tryWithSudo=true to try with sudo. WARNING: VM details, e.g. object alignment, reference size, compressed references info will be guessed. Running 64-bit HotSpot VM. Using compressed oop with 3-bit shift. Using compressed klass with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] ■クラスインスタンスのメモリ情報■ 24 HelloJol.HELLO_JOL_HOGE@12(4) HelloJol.HELLO_JOL_FUGA@16(4) size = 24 com.hhhhhskw.jol.HelloJol object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 05 c0 00 f8 (00000101 11000000 00000000 11111000) (-134168571) 12 4 String HelloJol.HELLO_JOL_HOGE (object) 16 4 String HelloJol.HELLO_JOL_FUGA (object) 20 4 (loss due to the next object alignment) Instance size: 24 bytes (estimated, add this JAR via -javaagent: to get accurate result) Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ■フィールドのメモリ情報■ HELLO_JOL_HOGE 4 String HelloJol.HELLO_JOL_HOGE@12(4) ■フィールドのメモリ情報■ HELLO_JOL_FUGA 4 String HelloJol.HELLO_JOL_FUGA@16(4) [HelloJol.HELLO_JOL_HOGE@12(4), HelloJol.HELLO_JOL_FUGA@16(4)]
【感想】
・継承関係にあるクラスのフィールドの中身までさかのぼってサイズ取得してくれるので便利。
・アプリケーション単位で特定の箇所でメモリサイズを取得する場合、インスタンスを適当に決めると、重複してサイズ取得する恐れがあるので、取得対象とするインスタンスは慎重に選ぶべき。
・VMSupport、GraphLayoutクラスを使用したサンプルは下記のソースを参照。
code-tools/jol: 4443d2696dcf /jol-samples/src/main/java/org/openjdk/jol/samples/
【参考】
[Java]オブジェクトの使用メモリを測る - Qiita