ScalaのHashMapに関する論文(Optimizing Hash-Array Mapped Tries for Fast and Lean Immutable JVM Collections)輪読会 in FOLIO メモその2 JVM CompressedOOPs編

本記事について

FOLIOでやった輪読会のメモです。

本論には関係ないが Optimizing Hash-Array Mapped Tries for Fast and Lean Immutable JVM Collections の以下の記載について深掘りする。

Due to the JVM’s 8-byte memory alignment, adding the hash code field to CHAMP does not increase its memory footprint.(5)

(脚注)5. This is valid for JVM instances with less than 32GB heaps with the CompressedOops option enabled (default)

目次

OOP とは

※ 本記事でJVMといった場合、HotSpot VMのことを指します。

JVMではObjectのインスタンスを作成しヒープに保存する際にメモリを割り当てる。この領域への参照やそれらに関する情報のことを OOP(Ordinary Object Pointer) と呼ぶ 。(参照先にはインスタンスのプロパティの値とかが入ってるイメージ。)

Java HotSpotの専門用語である「OOP」(Ordinary Object Pointer)は、オブジェクトへの管理ポインタです。

Java HotSpot™仮想マシンのパフォーマンスの向上

OOPはネイティブマシンポインタと同じサイズ(LP64システムなら64bit)になる。なおLP64 = long, pointerが64bit (intは32bit), ILP32 = int, long, pointer が32bitである。(see データ型モデル ‐ 通信用語の基礎知識

OOPについての解説は本記事ではこれ以上解説しないので詳しく知りたい人は Ordinary Object Pointer in JVM - Speaker Deck を見ると良い。

CompressedOops とは

ILP32システムでは最大ヒープサイズが4Gバイト弱(2^32バイト弱)になるが、多くのアプリケーションでこれは少なすぎる。 LP64システムなら大きなヒープを扱えるがポインタ型が大きくなるので、ILP32システムで実行する場合よりも約1.5倍程度大きくなることがある。この問題を改善したい。

※ 改善のモチベーションはメモリよりは主にキャッシュとかメモリ帯域幅などの都合が大きい。

モリーのコストは低いですが、最近では帯域幅およびキャッシュが不足しているため、4Gバイト制限を解決するためだけにヒープ・サイズが大幅に増加するのは望ましくありません。

Java HotSpot™仮想マシンのパフォーマンスの向上

ということで、OOP(ordinary object pointer)を圧縮することで上記のメモリオーバーヘッドを解消するための仕組みがCompressedOopsである。

圧縮方法

図解が HotSpot under the Hood にあるのでそちらも参照。

圧縮OOPを使った表現ではOOPは 32bitオブジェクトオフセット + base として表現される。

  • OOP = (圧縮oop * 8) + base
    • つまりOOP = (圧縮oop << 3) + base
  • JVMでのデフォルトでのオブジェクトのバイトアドレス境界は8byteなので8倍されている。
    • 余談: バイトアドレス境界は-XX:ObjectAlignmentInBytesで増やすことも出来る。 (java)
  • バイトオフセットではなくオブジェクトオフセットなのがポイント。これにより最大約32GBのヒープ・サイズをアドレス指定するために使用できる。
    • IL32相当の4G分の空間の場合、4Gオブジェクトオフセットまで表現できるので4G*8 = 32GBまでヒープアドレスを表現できることになる。

32GB以上のヒープを表現するためにはbaseアドレスの加算が必要。逆に言うと32GB未満ならbaseは不要で実際にbase=0とされて計算が省略されるようになっている。

  • 前述の-XX:ObjectAlignmentInBytes オプションの説明に、以下のような記載があるのでオブジェクトアラインメントをいじればbaseを使わずとも32GBよりも大きなヒープサイズを圧縮OOPで実現できそう。
    • このオプションにより、大きいJavaヒープ・サイズで圧縮ポインタを使用できます。
    • (java)
    • ただし、様々な最適化されているライブラリがalignment=8byteを期待している気がするので気軽にいじって早くなるのかは不明