Submit Search
「書ける」から「できる」になれる! ~Javaメモリ節約ノウハウ話~
6 likes
8,467 views
JustSystems Corporation
2017/11/18 JJUG CCC 2017 Fallでの発表資料です。 #jjug_ccc #ccc_g5
Software
Read more
1 of 28
1
2
3
4
5
6
7
8
9
10
Most read
11
12
13
14
15
16
Most read
17
18
19
20
21
22
23
24
25
Most read
26
27
28
More Related Content
PDF
Observableで非同期処理
torisoup
PDF
Unity開発で使える設計の話+Zenjectの紹介
torisoup
PDF
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
NTT DATA Technology & Innovation
PDF
詳説データベース輪読会: 分散合意その2
Sho Nakazono
PDF
PHPでWebSocketを実装してみてわかったこと
ksimoji
PDF
Java仮想マシンの実装技術
Kiyokuni Kawachiya
PDF
ClassLoader Leak Patterns
nekop
PDF
C#の強み、或いは何故PHPから乗り換えるのか
Yoshifumi Kawai
Observableで非同期処理
torisoup
Unity開発で使える設計の話+Zenjectの紹介
torisoup
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
NTT DATA Technology & Innovation
詳説データベース輪読会: 分散合意その2
Sho Nakazono
PHPでWebSocketを実装してみてわかったこと
ksimoji
Java仮想マシンの実装技術
Kiyokuni Kawachiya
ClassLoader Leak Patterns
nekop
C#の強み、或いは何故PHPから乗り換えるのか
Yoshifumi Kawai
What's hot
(20)
PDF
C++ マルチスレッド 入門
京大 マイコンクラブ
PDF
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
Yahoo!デベロッパーネットワーク
PDF
OpenStackで始めるクラウド環境構築入門(Horizon 基礎編)
VirtualTech Japan Inc.
PDF
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Toru Makabe
PDF
ゲーム開発者のための C++11/C++14
Ryo Suzuki
PDF
ObserverパターンからはじめるUniRx
torisoup
PDF
Reactive extensions入門v0.1
一希 大田
PDF
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
NTT DATA Technology & Innovation
PDF
プログラムの処方箋~健康なコードと病んだコード
Shigenori Sagawa
PDF
ELFの動的リンク
7shi
PDF
BuildKitの概要と最近の機能
Kohei Tokunaga
PDF
Redmine にいろいろ埋め込んでみた
Kohei Nakamura
PDF
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
PDF
人生がときめくAPIテスト自動化 with Karate
Takanori Suzuki
PDF
Linux女子部 systemd徹底入門
Etsuji Nakai
PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
PPTX
Jenkins と groovy
Kohsuke Kawaguchi
PDF
Steam ゲーム内購入 サーバーサイド実装について
KLab Inc. / Tech
PDF
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
Hironobu Isoda
PDF
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
SEGADevTech
C++ マルチスレッド 入門
京大 マイコンクラブ
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
Yahoo!デベロッパーネットワーク
OpenStackで始めるクラウド環境構築入門(Horizon 基礎編)
VirtualTech Japan Inc.
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Toru Makabe
ゲーム開発者のための C++11/C++14
Ryo Suzuki
ObserverパターンからはじめるUniRx
torisoup
Reactive extensions入門v0.1
一希 大田
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
NTT DATA Technology & Innovation
プログラムの処方箋~健康なコードと病んだコード
Shigenori Sagawa
ELFの動的リンク
7shi
BuildKitの概要と最近の機能
Kohei Tokunaga
Redmine にいろいろ埋め込んでみた
Kohei Nakamura
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
人生がときめくAPIテスト自動化 with Karate
Takanori Suzuki
Linux女子部 systemd徹底入門
Etsuji Nakai
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
Jenkins と groovy
Kohsuke Kawaguchi
Steam ゲーム内購入 サーバーサイド実装について
KLab Inc. / Tech
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
Hironobu Isoda
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
SEGADevTech
Ad
Similar to 「書ける」から「できる」になれる! ~Javaメモリ節約ノウハウ話~
(20)
PDF
RestKitの紹介 - Webサービスのクライアント実装補助フレームワーク -
次朗 永島
PPTX
Metaspace
Yasumasa Suenaga
PDF
asm.jsとWebAssemblyって実際なんなの?
Yosuke Onoue
PDF
JAMstackは眠らない
Kuniyoshi Tone
PDF
イマドキの現場で使えるJavaライブラリ事情
takezoe
PDF
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
NTT DATA Technology & Innovation
PDF
Apache Torqueについて
tako pons
PDF
Windows Server 2016 で作るシンプルなハイパーコンバージドインフラ (Microsoft TechSummit 2016)
Takamasa Maejima
PDF
PostgreSQL 12の話
Masahiko Sawada
PDF
WASM(WebAssembly)入門 ペアリング演算やってみた
MITSUNARI Shigeo
PDF
An Intelligent Storage?
Kohei KaiGai
PDF
20100930 sig startups
Ichiro Fukuda
PPTX
Elasticsearch 5.2とJava Clientで戯れる #elasticsearchjp
Yahoo!デベロッパーネットワーク
PDF
Grails 2.0.0.M1の話
Tsuyoshi Yamamoto
KEY
NVIDIA Japan Seminar 2012
Takuro Iizuka
PDF
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
normalian
PDF
GPUとSSDがPostgreSQLを加速する~クエリ処理スループット10GB/sへの挑戦~ [DB Tech Showcase Tokyo/2017]
Kohei KaiGai
PDF
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
Yoshiyuki Asaba
PDF
YugabyteDBを使ってみよう(NewSQL/分散SQLデータベースよろず勉強会 #1 発表資料)
NTT DATA Technology & Innovation
KEY
Web Operations and Perl kansai.pm#14
Masahiro Nagano
RestKitの紹介 - Webサービスのクライアント実装補助フレームワーク -
次朗 永島
Metaspace
Yasumasa Suenaga
asm.jsとWebAssemblyって実際なんなの?
Yosuke Onoue
JAMstackは眠らない
Kuniyoshi Tone
イマドキの現場で使えるJavaライブラリ事情
takezoe
PostgreSQL最新動向 ~カラムナストアから生成AI連携まで~ (Open Source Conference 2025 Tokyo/Spring ...
NTT DATA Technology & Innovation
Apache Torqueについて
tako pons
Windows Server 2016 で作るシンプルなハイパーコンバージドインフラ (Microsoft TechSummit 2016)
Takamasa Maejima
PostgreSQL 12の話
Masahiko Sawada
WASM(WebAssembly)入門 ペアリング演算やってみた
MITSUNARI Shigeo
An Intelligent Storage?
Kohei KaiGai
20100930 sig startups
Ichiro Fukuda
Elasticsearch 5.2とJava Clientで戯れる #elasticsearchjp
Yahoo!デベロッパーネットワーク
Grails 2.0.0.M1の話
Tsuyoshi Yamamoto
NVIDIA Japan Seminar 2012
Takuro Iizuka
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
normalian
GPUとSSDがPostgreSQLを加速する~クエリ処理スループット10GB/sへの挑戦~ [DB Tech Showcase Tokyo/2017]
Kohei KaiGai
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
Yoshiyuki Asaba
YugabyteDBを使ってみよう(NewSQL/分散SQLデータベースよろず勉強会 #1 発表資料)
NTT DATA Technology & Innovation
Web Operations and Perl kansai.pm#14
Masahiro Nagano
Ad
More from JustSystems Corporation
(20)
PDF
Spring Boot の Web アプリケーションを Docker に載せて AWS ECS で動かしている話
JustSystems Corporation
PDF
「技術内閣制度」〜2年間やってきて得られた事とこれから〜 #devsumi
JustSystems Corporation
PDF
事業に貢献する商品開発と その成長の仕組み作り ~これからのエンジニアに必要とされるスキルとは~
JustSystems Corporation
PDF
現役23名のPM:タイプ別マネジメントパターン
JustSystems Corporation
PPTX
JavaでインメモリSQLエンジンを作ってみた
JustSystems Corporation
PDF
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
JustSystems Corporation
PDF
JustTechTalk#11_スマイルゼミ顧客満足度への貢献
JustSystems Corporation
PDF
ピュアJavaだと思った?残念androidでした~いつからAndroidをJavaだと錯覚していた?~
JustSystems Corporation
PDF
最新のJava言語仕様で見るモジュールシステム #jjug
JustSystems Corporation
PDF
JustTechTalk#10 React開発における自動テスト実践
JustSystems Corporation
PDF
JustTechTalk#10windowsアプリでのテスト自動化事例
JustSystems Corporation
PDF
インパス! あのこれダメッス! ~Javaコードレビューの指摘ポイント10選~
JustSystems Corporation
PDF
AWS運用における最適パターンの徹底活用
JustSystems Corporation
PPTX
ジャストシステムのDevOps実例 今後の取り組み
JustSystems Corporation
PDF
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
JustSystems Corporation
PPTX
Kotlin is charming; The reasons Java engineers should start Kotlin.
JustSystems Corporation
PDF
CSSレイアウトでなぜ失敗するか?
JustSystems Corporation
PPTX
Selenium WebDriver + python で E2Eテスト自動化
JustSystems Corporation
PPTX
TypeScriptの大規模開発への適用
JustSystems Corporation
PDF
UX実現に向けた社内の取り組みについて-訴求ファーストによる商品開発-
JustSystems Corporation
Spring Boot の Web アプリケーションを Docker に載せて AWS ECS で動かしている話
JustSystems Corporation
「技術内閣制度」〜2年間やってきて得られた事とこれから〜 #devsumi
JustSystems Corporation
事業に貢献する商品開発と その成長の仕組み作り ~これからのエンジニアに必要とされるスキルとは~
JustSystems Corporation
現役23名のPM:タイプ別マネジメントパターン
JustSystems Corporation
JavaでインメモリSQLエンジンを作ってみた
JustSystems Corporation
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
JustSystems Corporation
JustTechTalk#11_スマイルゼミ顧客満足度への貢献
JustSystems Corporation
ピュアJavaだと思った?残念androidでした~いつからAndroidをJavaだと錯覚していた?~
JustSystems Corporation
最新のJava言語仕様で見るモジュールシステム #jjug
JustSystems Corporation
JustTechTalk#10 React開発における自動テスト実践
JustSystems Corporation
JustTechTalk#10windowsアプリでのテスト自動化事例
JustSystems Corporation
インパス! あのこれダメッス! ~Javaコードレビューの指摘ポイント10選~
JustSystems Corporation
AWS運用における最適パターンの徹底活用
JustSystems Corporation
ジャストシステムのDevOps実例 今後の取り組み
JustSystems Corporation
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
JustSystems Corporation
Kotlin is charming; The reasons Java engineers should start Kotlin.
JustSystems Corporation
CSSレイアウトでなぜ失敗するか?
JustSystems Corporation
Selenium WebDriver + python で E2Eテスト自動化
JustSystems Corporation
TypeScriptの大規模開発への適用
JustSystems Corporation
UX実現に向けた社内の取り組みについて-訴求ファーストによる商品開発-
JustSystems Corporation
「書ける」から「できる」になれる! ~Javaメモリ節約ノウハウ話~
1.
「書ける」から「できる」になれる! ~Javaメモリ節約ノウハウ話~ JJUG CCC 2017
Fall 2017/11/18 #jjug_ccc #ccc_g5 1
2.
JUSTSYSTEMS 自己紹介 • 株式会社ジャストシステム 猪鼻哲也 •
担当商品履歴 • MS-DOS上のOffice系アプリケーション • Windows上のOffice系アプリケーション • Windows上の情報活用系アプリケーション • ストレージ系インターネットサービス • オンプレミス文書管理系サーバ • オンプレミス情報活用系サーバ • ... • Java歴18年 • 低レイヤーの実装まわりが好き 2
3.
JUSTSYSTEMS 本日の内容 • Javaオブジェクトの構造 • メモリ使用量の削減 •
ライブラリの利用 • まとめ • 付録 3
4.
JUSTSYSTEMS Java進化の歴史 • 機能面はもちろんのこと、性能面の進化が普及できた 大きな要因(特にサーバーサイド) • 速度はJIT/HotSpotの進化で商用レベルに(JDK1.3~) •
メモリについては、H/Wの進化と64bit VMにより、over 2GB の大容量が実現可能に • エンタープライズ検索やインメモリDBによる集計・分析といっ た、昔では考えられなかった機能も実現 <弊社製品例> https://www.justsystems.com/jp/products/cbes https://www.justsystems.com/jp/products/actionista/ 4
5.
JUSTSYSTEMS メモリ不足はサービス安定運用の大敵 • メモリ使用量やリークに注意しないとSTW(Stop the world)やOOM(OutOfMemoryError)が発生 •
リークしてなくても-Xmxの8~9割程度使ってしまうと メモリ確保/GCの負荷上昇でスループットが落ちてく る(経験上) • スループット低下やサービスダウン→緊急の対応が必要 最初からメモリ使用量を抑えておくに越したことはない 5
6.
JUSTSYSTEMS Javaオブジェクトの構造 6
7.
JUSTSYSTEMS Javaオブジェクトの構造 /* フィールドのオフセットをsun.misc.Unsafe.objectFieldOffset()で取得すると、 管理用データのサイズを反映した値が返る */ class
A { public int a; }; ... Unsafe unsafe = ...(略); // sun.misc.Unsafeの”theUnsafe”をリフレクションで取得 Field aField = A.class.getDeclaredField(“a”); // class Aのフィールドaを取得 long offset = unsafe.objectFieldOffset(aField); // フィールドaのオフセットを取得 // 32bitVMで8 (4 + 4) // 64bitVM -XX:+UseCompressedOopsで12 (8 + 4) // 64bitVM -XX:–UseCompressedOops(または-Xmx32g以上)で16 (8 + 8) Javaソースで定義 したフィールド... (8バイトアラインメント) _mark _klass • 管理用のデータ領域を先頭に持つ • _mark → オブジェクトの状態 • 32bit VMの場合4バイト、64bit VMで8バイト • _klass →クラスデータへの参照 • 32bit VMの場合4バイト、64bit VMで8バイト • 64bitでもCompressedOops(オブジェクト参照を圧縮す る仕組み)が有効な場合は4バイト ど の オ ブ ジ ェ ク ト も 必 ず 持 っ て い る 領 域 7
8.
JUSTSYSTEMS 基本型とラッパークラス • ラッパークラスのオブジェクトは管理領域+保持している基 本型サイズ+パディングのメモリを消費 基本型とそのサイズ(バイト) 対応するラッパークラスとそのメモリ使用量(バイト) 型名
サイズ クラス名 32bit JVM 64bit JVM 32GB未満 64bit JVM 32GB以上 boolean 1 Boolean 16 16 24 byte 1 Byte 16 16 24 char 2 Character 16 16 24 short 2 Short 16 16 24 int 4 Integer 16 16 24 float 4 Float 16 16 24 long 8 Long 16 24 24 double 8 Double 16 24 24 8 boolean Boolean(32bit JVM) Boolean(64bit JVM<32GB) Boolean(64bit JVM≧32GB) val ue _mark _klass _mark _mark val ue _klass val ue _klass val ue long Long(32bit JVM) Long(64bit JVM<32GB) Long(64bit JVM≧32GB) value _mark _klass _mark _mark value _klass _klass value value 詳細は チラシで
9.
JUSTSYSTEMS 基本型とラッパークラス • -Xmx32g(厳密には-Xmx32767m~)を境にメモリ使 用量が増える理由 圧縮Oops(CompressedOops)が無効になり、オブジェクト参 照(klassヘッダー)が4→8バイトになるため •
4バイト(32bit)で識別可能なアドレス空間は4GB(== 2^32) • Javaオブジェクトのアドレスは8バイトでアラインメントされているため、 下位3bitは常に0 • (bbbbbbbb bbbbbbbb bbbbbbbb bbbbb000のビットパターン) • 3bitシフトで35bitのアドレス空間を32bitで識別できる(35bit→32GB) • (-Xmx32g以下でも-XX:-UseCompressedOopsで無効にできる) 9
10.
JUSTSYSTEMS Javaオブジェクトの構造(再) • たいていの場合、単一ではなくオブジェクト内にオブジェク トへの参照を持っている • 例えば形態素解析辞書の場合 •
一つの単語は表記・品詞・解析用情報からなる class 単語 { String[] 表記; // 表記ゆれ対応のため複数 int 品詞; int 解析用パラメータ; } • 辞書は単語の集合 class 辞書 { 単語[] words = new 単語[100万とか]; } 10
11.
JUSTSYSTEMS Javaオブジェクトの構造(再) "バイオリン", "ヴァイオリン"表記を持つ単語の場合 • 132バイト中58バイト(44%)が管理情報またはパディング •
構造はJVMの実装により異なる(上記は32bit JVM) • 32bitポインタ/8バイトアラインメント オブジェクトの数が増えると、想定以上にメモリ消費量が増大 11 class 単語 class String[] String char[] 単語: _mark _klass _mark _klass _mark _klass _mark _klass 表記: 品詞:xxxx length:2 value: hash:xx length:5 'バ' 'イ' 解析:yyyy value: value: 'オ' 'リ' 'ン' String char[] _mark _klass _mark _klass value: hash:yy length:6 'ヴ' 'ァ' 'イ' 'オ' 'リ' 'ン'
12.
JUSTSYSTEMS いろいろなオブジェクトのメモリ使用量 クラス/オブジェクト 32bit JVM 64bit
JVM 32GB未満 64bit JVM 32GB以上 new String("https://[^/]+/") ※Java8 56 72 88 new String("https://[^/]+/") ※Java9 56 72 "https://[^/]+/".toCharArray() 40 48 56 "https://[^/]+/".getBytes("UTF-8") 32 32 40 Pattern.compile("https://[^/]+/") 1080 1128 1256 new Date() 24 24 32 new Timestamp() 24 32 40 Calendar.getInstance() ※GregorianCalendar 424 448 544 ZonedDateTime.now() 88 120 152 LocalDateTime.now() 48 72 80 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S") 1232 1296 1880 DateTimeFormatter.of("yyyy-MM-dd HH:mm:ss.S") 432 456 704 • StringはJava9でサイズが小さくなった(Latin-1の文字は1byteで保持するため) • Patternなどはstaticに持っておくとよい。 • GregorianCalendarが意外と大きい。 • SimpleDateFormatはスレッドセーフでないので、同期化するかDateTimeFormatterに乗り換える。 • etc... 12 詳細は チラシで
13.
JUSTSYSTEMS メモリ使用量の削減 13
14.
JUSTSYSTEMS 基本型を使う • 単語を全て基本型の配列に押し込む class 辞書(メモリ節約版)
{ char[] 全単語の表記; // 表記揺れ数→表記長→表記の順に格納 int[] 全単語の表記への開始位置の配列; int[] 品詞の配列; int[] 解析用パラメータの配列; } • 前述の辞書のメモリ使用量は・・・3分の1以下に! • ただし、ソース可読性・メンテナンス性が犠牲に・・・ クラス メモリ使用量 [MB] 32bitVM 64bitVM 32GB未満 64bitVM 32GB以上 辞書 109.3 132.0 180.0 辞書(メモリ節約版) 32.0 32.0 32.0 14
15.
JUSTSYSTEMS 基本型の配列をさらに詰める • Boolean[ ]
→ 4または8バイト x 要素数 • Boolean.TRUE/FALSEを格納した場合。new Boolean(true/false)はやめましょう 。 • boolean[ ] → 1バイト x 要素数 • BitSet → 1ビット x 要素数 (内部はlong[ ]配列) • 要素数100万の場合、BitSetはBoolean[ ]の16分の1以下、 125KBに! 32bitVM 64bitVM 32GB未満 64bitVM 32GB以上 new Boolean[100万] 4MB 4MB 8MB new boolean[100万] 1MB 1MB 1MB new BitSet(100万) 125kB 125kB 125kB • BitSetをさらに圧縮する方法もあるが、難しいのでここでは割愛 15 詳細は チラシで
16.
JUSTSYSTEMS 基本型の配列をさらに詰める • booleanをBitSetに詰めたのと同様、整数配列の最小値~最大値が N bit(N≪整数型のビット幅)で表現できるとあらかじめ分かっている場合、配列 に隙間なく詰め込むことで圧縮できる(ただし取得にbit演算が必要になる) •
データ依存で効果が異なる • どんなデータもコンスタントに圧縮できる方法はなかなかない • 伸張速度も重要、用途によってはランダムアクセスも必要 long: val1 long: val2 long: val3 long: val4 val1 val2 val3 val4 ... ... long値の配列の最小値~最大値が64bitよりも小さなbitで表現できる場合 値のバリエーションが少ない場合も、値→IDの変換表を作ることでも圧縮 ID 値 1 123456 2 98765432 3 123456789 123456789 123456 98765432 123456 3 1 2 1 ... ... 16
17.
JUSTSYSTEMS ライブラリの利用 17
18.
JUSTSYSTEMS Collection @since 1.2 •
Java Collection Framework • List, Map, Set等の頻出するデータ集合に対する 統一されたインターフェイスを提供 • 検索やソート等の高性能実装 • 一般には、使いやすく、高品質、高性能 • ただし、メモリ使用量に関しては・・・ 18
19.
JUSTSYSTEMS Autoboxing @since 1.5 •
一見基本型を使っているようだがラッパークラスに Set<Integer> set = new HashSet<Integer>(); set.add(1234); // 実際にはnew Integer(1234) が追加 • 基本型を指定しても、自動的にIntegerが生成され格納さ れる(4バイトではなく16バイト以上消費) • さらに、HashSet/HashMapは内部でMap.Entryを生成して key/valueを格納するため、その分のメモリも消費・・・ 19
20.
JUSTSYSTEMS 省メモリコレクションライブラリ • fastutil, Eclipse(GS)
Collections, HPPC, koloboke, troveなど • Map/Set<? extends Number>の値を基本型で持つことで省メモリ化 • JDKのHashMap<K,V>/HashSet<K>に比べ1/5以下のメモリ使用量 ■100万個のint値を保持した集合のメモリ使用量と検索時間(実測値) コレクションクラス メモリ使用量 [MB] 検索時間 [ns/エントリ] 32bitVM 64bitVM 32GB未満 64bitVM 32GB以上 32bitVM 64bitVM 32GB未満 64bitVM 32GB以上 int[ ] (検索はバイナリサーチ) 4.0 4.0 4.0 165 154 159 java.util.HashSet<Integer> 48.4 56.4 88.8 166 68 74 it.unimi.dsi.fastutil.ints.IntOpenHashSet *1 8.4 8.4 8.4 30 39 25 org.eclipse.collections.impl.set.mutable. primitive.IntHashSet *2 8.4 8.4 8.4 53 50 33 com.koloboke.collect.impl.hash. MutableLHashIntSet *3 8.4 8.4 8.4 31 23 23 com.carrotsearch.hppc.IntHashSet *4 8.4 8.4 8.4 35 28 21 *1 fastutil → http://fastutil.di.unimi.it/ *2 Eclipse Collections → https://www.eclipse.org/collections/ja/ *2 koloboke → https://koloboke.com/ *4 hppc → https://labs.carrotsearch.com/hppc.html 20
21.
JUSTSYSTEMS 省メモリコレクションライブラリ • オブジェクトを入れる場合も、key/valueの格納にMap.Entry<K,V>を使わず Object[] に詰め込んでいるため、JDKのHashMap/HashSetより省メモリ //
char[]とbyte[]を両方扱えるHash.Strategy(fastutil用) // ObjectOpenCustomHashSetに設定して利用 // ※Latin-1の文字列の場合byte[ ]、 // それ以外はchar[ ] をput()/add()する class PrimitiveArrayHashStrategy implements Hash.Strategy<Object> { public int hashCode(Object o) { if (o == null) { return 0; } if (o instanceof byte[]) { return Arrays.hashCode((byte[]) o); } else if (o instanceof char[]) { return Arrays.hashCode((char[]) o); } else { /* エラー */ } } public boolean equals(Object a, Object b) { if (a == b) { return true; } if (a instanceof byte[]) { return b instanceof byte[] && Arrays.equals((byte[]) a, (byte[]) b); } else if (a instanceof char[]) { return b instanceof char[] && Arrays.equals((char[]) a, (char[]) b); } return false; } } コレクションクラス メモリ使用量 [MB] 32bitVM 64bitVM 32GB未満 64bitVM 32GB以上 Java8 Java8 Java9 Java8 Java9 HashSet<String> 111.6 128.4 104.4 168.8 144.8 ObjectOpenHashSet <String>(fastutil) 87.6 96.4 72.4 120.8 96.8 ObjectOpenCustom HashSet<Object> *1 48.4 48.4 48.4 64.8 64.8 ■Latin-1の文字列100万個を保持したSetのメモリ使用量 • さらに、fastutilのHash.StrategyやEclipse(GS) CollectionsのHashingStrategy, kolobokeのEquivalence を使うと、hashCode()やequals()を持たないクラスのオブ ジェクトをMapやSetに格納できる • プリミティブ配列も使えるので、Stringの代わりにchar[ ] やbyte[ ]を入れられるMap/Setが作れる *1 全てbyte[ ]で格納されているため、省メモリ 21
22.
JUSTSYSTEMS 省メモリコレクションライブラリ • (先ほどの辞書クラスと同様)文字列ごとのbyte[ ]
を1つのbyte[ ]に詰め込む HashMap/HashSetを考えると、さらにメモリが節約できる(→32.5MB) • さらに圧縮するなら、アルゴリズム/データ構造から変える必要がある // byte[]に全文字列を詰め込むHashSet/Map class ByteArrayStringHashSet { // Latin-1かどうかと文字列長と文字列本体を // 詰め込んだbyte配列 private byte[] buffer; // エントリごとのbufferへのオフセット // ハッシュ値ごとにまとめて格納 private int[] offsets; // 詳細は →https://en.wikipedia.org/wiki/Hash_table#O pen_addressing // Mapとして使う場合に値を格納する配列 // private Object[] values; } コレクションクラス メモリ使用量 [MB] 32bitVM 64bitVM 32GB未満 64bitVM 32GB以上 Java8 Java8 Java9 Java8 Java9 HashSet<String> 111.6 128.4 104.4 168.8 144.8 ObjectOpenHashSet <String>(fastutil) 87.6 96.4 72.4 120.8 96.8 ObjectOpenCustom HashSet<Object> (前ページ) 48.4 48.4 48.4 64.8 64.8 ByteArrayStringHash Set (右図) 32.5 32.5 32.5 32.5 32.5 org.trie4j.louds. TailLOUDSTrie *1 24.6 24.7 24.5 24.7 24.5 ■Latin-1の文字列100万個を保持したSetのメモリ使用量 • 例えばLOUDS Trieなど(→ 24.6MB) *1 trie4j → https://github.com/takawitter/trie4j 22
23.
JUSTSYSTEMS まとめ • Javaのオブジェクトは1つ1つ参照としてしか生成できず、大量の インスタンスを生成するとメモリ消費のオーバーヘッドが無視でき なくなる • メモリ使用量が高止まりするとガベージコレクションの負荷も上がってしまう。 •
用途によってはプリミティブ型や高効率のOSSライブラリを活用す ることでメモリ使用量を節約できる • プリミティブ型を使うとソースの可読性やメンテナンス性が犠牲になる場合も。 • 実装時間が余計にかかったり、バグが残存しやすいのも悩みどころ。 • いくらがんばってもメモリに乗らないものは乗らない • コレクションを使うときに、何をどれくらいの入れるかやスコープ・ライフサイクルを 常に意識することが大切。 • そのためにもメモリ使用量を見積もったり計測するノウハウを持っておく。 • 乗らないものはあきらめて一時ファイルやDBを使う。 結局は適材適所 23
24.
JUSTSYSTEMS 付録 24
25.
JUSTSYSTEMS メモリ使用量の計測方法 ① Runtime.totalMemory() –
Runtime.freeMemory() • 一番お手軽。GC前のメモリも計測されるので、System.gc()してから計測する。(が、頻繁に計 測すると性能に影響が) ② MemoryMXBean (ManagementFactory.getMemoryMXBean()) • init, used, committed, max がそれぞれ取得可能。 ③ MemoryPoolMXBean (ManagementFactory.getMemoryPoolMXBeans()) • Eden, Survivor, Tenuredそれぞれ取得可能 (G1GCだと名前が変わる。 G1 Old Genとか) ④ com.sun.management.ThreadMXBean (Oracle JDK限定) • getThreadAllocatedBytes()でオブジェクト生成前後のヒープ量が差分が取れる。 • オブジェクト生成で一時的に確保されたヒープも計測されてしまうようなので注意が必要。 ⑤ Instrumentation.getObjectSize() • オブジェクトの正確なメモリ使用量が計測可能。 • premain()を実装したjarを-javaagent:...でJVM引数に指定する。 • 参照先のオブジェクトは計測できない →Reflectionを駆使して参照を辿りながら計測する必要あり。 ⑥ sun.misc.Unsafe.objectFieldOffset(Field f) • Fieldのオフセットが取得できる→全フィールドのオフセットの最大値+サイズでオブジェクトの サイズが計測できる。(アラインメントの考慮は必要) • 参照先をReflectionで辿って合計する必要があるのはInstrumentationと同じ。 25
26.
JUSTSYSTEMS 今後に向けて • JEP 169:
Value Objects http://openjdk.java.net/jeps/169 • クラスインスタンスの配列がメモリ上で連続して取れる • new 単語[100万]でもメモリ効率が落ちない。 • ネストするオブジェクト(単語.表記など)の扱いは別途工夫する必要があるかも。 • mark/klassのオーバーヘッドがなく、メモリ上でも近接しているため速度向上も期待できる • JEP 218: Generics over Primitive Types http://openjdk.java.net/jeps/218 • Map<int, int>とか。実装はサードパーティ任せ? • Array 2.0(Project Panama) http://openjdk.java.net/projects/panama/ • 2次元配列(従来だと1次元配列のオブジェクト配列)をメモリ上で連続して確保。 • メモリ効率を上げるためにnew int[m x n] のように1次元に詰め込んでいたのが、普通の2次 元配列(int[m][n])のようにでき、可読性と性能向上が期待できる。 • これらの導入で、自然言語処理や大規模データ処理でますますJavaが使え るようになるはず・・・ 26
27.
JUSTSYSTEMS その他の小技 • 省メモリな固定数コレクション • 空の場合、Collections.emptyList()/emptySet()/emptyMap() •
シングルトンの場合、 Collections.singletonList()/singleton()/singletonMap() • 2個以上の場合、Eclipse Collectionsの org.eclipse.collections.impl.list.fixed.DoubletonListなど • 同じオブジェクトをN個返す場合、Collections.nCopies(Object o) • Enumの場合、HashMap/SetよりEnumMap/Setが省メモリ • 数値型オブジェクトのキャッシュ • -128(Characterの場合は0)~127の場合、 Byte/Short/Character/Integer/Longはstaticにキャッシュされたインスタ ンスを返す • Integerのみ、-XX:AutoBoxCacheMax=<size>で上限を増やせる。 • BigDecimalの0~10も同様。BigIntegerは-1,0,1,2,10だけ。 27
28.
JUSTSYSTEMS ご清聴ありがとうございました 今回はメモリ節約についてご紹介しました 株式会社ジャストシステムでは多種多様な商品を 開発しており、さまざまな技術を活用しています 興味のある方、お声がけください • 「できる」になれるコンテンツ:Java100本ノック • https://github.com/JustSystems/java-100practices •
ジャストシステムのエンジニア特集ページ • https://www.justsystems.com/jp/employ/engineer/ 28