世界を動かす技術を、日本語で。

JVMオプションエクスプローラー

概要

OpenJDKの各種VMオプションの概要と設定内容を日本語で簡潔にまとめたリストです。 各オプションのバージョン、型、デフォルト値、用途、関連ファイルを整理。 GC、コンパイラ、ランタイムなど幅広い分野の設定項目を含む。 非推奨や廃止予定のオプションも明記。 用途や効果が分かりやすい体言止めで記載。

OpenJDK VM オプション一覧(A〜B)

  • AOTLibrary

    • OpenJDK9、型: ccstr、ランタイム用、デフォルト: NULL、用途: experimentalなAOTライブラリ指定、定義ファイル: share/runtime/globals.hpp
  • AVX3Threshold

    • OpenJDK11、型: intx、x86専用、デフォルト: 4096、範囲: 0〜max_jint、用途: AVX512命令を利用する最小配列サイズ(バイト単位)、定義ファイル: cpu/x86/globals_x86.hpp
  • AbortVMOnCompilationFailure

    • OpenJDK11、型: bool、ランタイム用、デフォルト: false、用途: メソッドのコンパイル失敗時にVMを強制終了、定義ファイル: share/runtime/globals.hpp
  • AbortVMOnExceptionMessage

    • OpenJDK6、型: ccstr、ランタイム用、デフォルト: NULL、用途: AbortVMOnExceptionで指定した例外のメッセージ一致時にVMを強制終了、定義ファイル: share/runtime/globals.hpp
  • AbortVMOnException

    • OpenJDK6、型: ccstr、ランタイム用、デフォルト: NULL、用途: 指定例外発生時にVMを強制終了、例: java -XX:AbortVMOnException=java.lang.NullPointerException Foo、定義ファイル: share/runtime/globals.hpp
  • AbortVMOnSafepointTimeout

    • OpenJDK11、型: bool、ランタイム用、デフォルト: false、用途: Safepoint到達失敗時にVMを強制終了、定義ファイル: share/runtime/globals.hpp
  • AbortVMOnVMOperationTimeoutDelay

    • OpenJDK11、型: intx、ランタイム用、デフォルト: 1000、範囲: 0〜max_intx、用途: AbortVMOnVMOperationTimeout用の遅延(ミリ秒)、定義ファイル: share/runtime/globals.hpp
  • AbortVMOnVMOperationTimeout

    • OpenJDK11、型: bool、ランタイム用、デフォルト: false、用途: VM操作が期限内に完了しない場合にVMを強制終了、定義ファイル: share/runtime/globals.hpp
  • ActiveProcessorCount

    • OpenJDK10、型: int、GC用、デフォルト: -1、用途: VMが使用・報告するCPU数の指定、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizeDecrementScaleFactor

    • OpenJDK6、型: uintx、GC用、デフォルト: 4、範囲: 1〜max_uintx、用途: サイズ縮小時のスケールダウン係数、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizeMajorGCDecayTimeScale

    • OpenJDK6、JDK26で非推奨、JDK27で廃止、型: uintx、GC用、デフォルト: 10、用途: Major GCコスト減衰の時間スケール、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizePolicyCollectionCostMargin

    • OpenJDK6、JDK23で非推奨、JDK24で廃止、型: uintx、GC用、デフォルト: 50、範囲: 0〜100、用途: コレクションコストがマージン内の場合の処理、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizePolicyGCTimeLimitThreshold

    • OpenJDK6、型: uintx、GC用、デフォルト: 5、範囲: 1〜max_uintx、用途: GC時間制限発動までの連続コレクション数、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizePolicyInitializingSteps

    • OpenJDK6、JDK26で非推奨、JDK27で廃止、型: uintx、GC用、デフォルト: 20、用途: ヒューリスティック使用ステップ数、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizePolicyOutputInterval

    • OpenJDK6、JDK26で非推奨、JDK27で廃止、型: uintx、GC用、デフォルト: 0、用途: 情報出力の間隔(0は出力なし)、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizePolicyReadyThreshold

    • OpenJDK6、型: uintx、GC用、デフォルト: 5、用途: 適応サイズ調整開始までのコレクション数、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizePolicyWeight

    • OpenJDK6、型: uintx、GC用、デフォルト: 10、範囲: 0〜100、用途: 指数リサイズへの重み付け、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveSizeThroughPutPolicy

    • OpenJDK6、JDK26で非推奨、JDK27で廃止、型: uintx、GC用、デフォルト: 0、用途: スループット目標の世代サイズ変更ポリシー、定義ファイル: share/gc/shared/gc_globals.hpp
  • AdaptiveTimeWeight

    • OpenJDK6、JDK26で非推奨、JDK27で廃止、型: uintx、GC用、デフォルト: 25、範囲: 0〜100、用途: 適応ポリシーでの時間重み、定義ファイル: share/gc/shared/gc_globals.hpp
  • AggressiveHeap

    • OpenJDK10、JDK26で非推奨、JDK27で廃止、JDK28で削除、型: bool、GC用、デフォルト: false、用途: 長時間・大規模アプリ向けヒープ最適化、定義ファイル: share/gc/shared/gc_globals.hpp
  • AggressiveOpts

    • OpenJDK6、JDK11で非推奨、JDK12で廃止、JDK13で削除、型: bool、ランタイム用、デフォルト: false、用途: (非推奨)積極的最適化の有効化、定義ファイル: share/runtime/globals.hpp
  • AggressiveUnboxing

    • OpenJDK8、型: bool、C2用、デフォルト: false、用途: ボクシング除去最適化制御、定義ファイル: share/opto/c2_globals.hpp
  • AliasLevel

    • OpenJDK6、JDK19で非推奨、JDK20で廃止、JDK21で削除、型: intx、C2用、デフォルト: 3、範囲: 0〜3、用途: エイリアス分割レベル、定義ファイル: share/opto/c2_globals.hpp
  • AlignVector

    • OpenJDK7、型: bool、C2用、デフォルト: true、用途: ループ内のベクトルストア/ロードのアラインメント、定義ファイル: share/opto/c2_globals.hpp
  • AllocateHeapAt

    • OpenJDK10、型: ccstr、ランタイム用、デフォルト: NULL、用途: Java Heapのバックストア用一時ファイルディレクトリ指定、定義ファイル: share/runtime/globals.hpp
  • AllocateInstancePrefetchLines

    • OpenJDK6、型: intx、ランタイム用、デフォルト: 1、範囲: 1〜64、用途: インスタンス割り当て時のプリフェッチライン数、定義ファイル: share/runtime/globals.hpp
  • AllocatePrefetchDistance

    • OpenJDK6、型: intx、ランタイム用、デフォルト: -1、用途: 割り当てポインタ先読み距離、-1は自動判定、定義ファイル: share/runtime/globals.hpp
  • AllocatePrefetchInstr

    • OpenJDK6、型: intx、ランタイム用、デフォルト: 0、用途: 割り当てポインタ用プリフェッチ命令指定、定義ファイル: share/runtime/globals.hpp
  • AllocatePrefetchLines

    • OpenJDK6、型: intx、ランタイム用、デフォルト: 3、範囲: 1〜64、用途: 配列割り当て時のプリフェッチライン数、定義ファイル: share/runtime/globals.hpp
  • AllocatePrefetchStepSize

    • OpenJDK6、型: intx、ランタイム用、デフォルト: 16、範囲: 1〜512、用途: プリフェッチ命令のステップサイズ(バイト単位)、定義ファイル: share/runtime/globals.hpp
  • AllocatePrefetchStyle

    • OpenJDK6、型: intx、ランタイム用、デフォルト: 1、範囲: 0〜3、用途: プリフェッチスタイル指定、定義ファイル: share/runtime/globals.hpp
  • AllowExtshm

    • OpenJDK9、型: bool、AIX用、デフォルト: false、用途: EXTSHM=ONでのVM実行許可、定義ファイル: os/aix/globals_aix.hpp
  • AllowJNIEnvProxy

    • OpenJDK6、JDK13で非推奨、JDK14で廃止、JDK15で削除、型: bool、ランタイム用、デフォルト: false、用途: jdbx用JNIEnvプロキシ許可、定義ファイル: share/runtime/globals.hpp
  • AllowNonVirtualCalls

    • OpenJDK6、JDK11で非推奨、JDK12で廃止、JDK13で削除、型: bool、ランタイム用、デフォルト: false、用途: ACC_SUPERフラグ準拠・invokenonvirtual許可、定義ファイル: share/runtime/globals.hpp
  • AllowParallelDefineClass

    • OpenJDK6、型: bool、ランタイム用、デフォルト: false、用途: パラレルクラスローダーでのdefineClass並列化許可、定義ファイル: share/runtime/globals.hpp
  • AllowUserSignalHandlers

    • OpenJDK6、型: bool、ランタイム用、デフォルト: false、用途: アプリケーション側シグナルハンドラのインストール許可(Solaris & Linux専用)、定義ファイル: share/runtime/globals.hpp
  • AllowVectorizeOnDemand

    • OpenJDK9、型: bool、C2用、デフォルト: true、用途: VectorizeMethodでのベクトル化抑制、定義ファイル: share/opto/c2_globals.hpp
  • AlwaysActAsServerClassMachine

    • OpenJDK6、JDK26で非推奨、JDK27で廃止、JDK28で削除、型: bool、GC用、デフォルト: false、用途: 常にサーバークラスマシンとして動作、定義ファイル: share/gc/shared/gc_globals.hpp
  • AlwaysAtomicAccesses

    • OpenJDK9、型: bool、ランタイム用、デフォルト: false、用途: 全変数アクセスを常にアトミックに、定義ファイル: share/runtime/globals.hpp
  • AlwaysCompileLoopMethods

    • OpenJDK6、型: bool、ランタイム用、デフォルト: false、用途: ループを含むメソッドを必ずコンパイル、定義ファイル: share/runtime/globals.hpp
  • AlwaysIncrementalInline

    • OpenJDK7、型: bool、C2用、デフォルト: false、用途: インライン化を逐次的に実行、定義ファイル: share/opto/c2_globals.hpp
  • AlwaysLockClassLoader

    • OpenJDK6、JDK17で非推

Hackerたちの意見

1843個のオプションは多すぎるよ。考えられる組み合わせや相互作用を全部考慮するなんて無理だし、テストなんてなおさら無理。最近は、gofmtみたいな意見がはっきりしたツールのありがたみがわかるようになったよ。何百も何千も調整が必要なツールとは違ってね。

面接で受けたオタククイズの一つは、「GNU lsのフラグになっていない文字とそのケースは何か」だったな。

機能や使い方が増えたからって、別にいいじゃん。例えば、ツールに別のガベージコレクタを使いたいって思うこともあるし。

現代性がツールが意見を持っているかどうかに影響するとは思わないな。

gofmtがJVMと比べられるのはどの辺り?実際、オプションの数は君が言った1843よりずっと少ないよ。このリストには、複数のアーキテクチャのために存在する重複がたくさんあるからね。例えば、BackgroundCompilationはOpenJDK 25のページで8行も出てくる:aarch64、arm、ppc、riscv、s390、x86、そしてアーキテクチャなしで2回も。

JavaがいろんなOS環境(Oracle、Redhat、Windows、RISC/ARM/x86)で動く必要があるから、ユーザーの制約やビジネス要件も影響してるんだよね。ある意味、このJVMオプションのリストはJavaがどれだけ成功したかを示してる。みんな自分のやり方で動かすためのオプションが必要なんだ。Java開発者としては、キャリアの中で多分10~15個くらいしか使ったことないけど、一番変わってて面白かったのは、古いSun MicrosystemsのSolarisサーバーでiPlanetを動かしてた時のJava EEサービス用のやつかな。このサーバーは他のバックオフィスシステムとリソースを共有してたから、メモリ不足になりやすかったんだ。幸い、これを処理するJVMオプションがあった! -XX:OnOutOfMemoryError="" そんなに重要じゃなかったから、全体を再起動させるために使ってたんだけど、そうするとまた生き返ったりしてね。時々、遊び半分で「Immah eaten all your bytez I ded now, please reboot me」みたいな面白いIRCメッセージを送らせたりしてた。

考えられる組み合わせや相互作用を全部考慮するなんて無理だし、テストなんてなおさら無理。64ビットの掛け算に対しても、誰も全ての入力をテストしたことなんてないよ。サンプルを取ることはできるけど。

システム管理者として、開発者じゃないけど、JavaはWindowsと同じくらい嫌い。Javaアプリが出すエラーメッセージは、解読しなきゃいけない暗号みたいなもんだよ。例えば、「TLSハンドシェイク失敗」じゃなくて「ERROR: PKIX失敗」みたいな感じ。だから、PKIXがPKIを指してるってわかるまで考えなきゃいけないし、失敗したドメインを教えてくれたらすごくわかりやすいのに。結局、推測ゲームをしなきゃならないんだ。

これまで存在したすべてのオプションが含まれてるよ。開発中に使われるデバッグビルド専用のオプションや診断オプションもある。今でも数百の非診断の「プロダクト」フラグが存在してるけど、大半は意図的にドキュメント化されてない(リストはソースコードから作成されてる [1])。コンパイラやリンカの設定フラグに似たようなもので、Javaではコンパイルとリンクがランタイムで行われるから、主にリソース定数に関するものだよ。手動で設定されることはほとんどないけど、変わった環境や条件があれば役立つこともある。

gofmtとの比較は意味がないよ。もしGoに無数のコンパイラ実装があったら(JVMのターゲット環境のアナロジーとして)、それぞれが異なるパフォーマンス特性や動作の違いを持ってたら、gofmtにもたくさんのオプションがあったはずだよ。JVMはオペレーティングシステムみたいなもんだ。もっと良い比較はLinuxカーネルのパラメータだね。

Goの哲学には共感するけど、このコメントはちょっとズレてる気がするし、ある種の未熟さを示してるね。これらのフラグの多くはGODEBUGに相当する。GODEBUGには1843個のオプションはないけど、いくつあるか知ってる?GODEBUGを使ったことある?(多分ないと思うから、未熟さが出てるんだろうね) 使ったことがないからって、必要ないから削除すべきだと思う?

あなたのサイトで言ってる「Optimizing Java」本の第2版が出たよ。

彼はおそらく知ってるだろうね、だって彼は著者の一人だから。

これは、私のiPhone/iPad用Java IDE「CodeBrew」の開発にめっちゃ役立ちそう。裏ではフルのOpenJ9 JVMが動いてて、ちゃんと動かすためにオプションを色々いじらなきゃいけなかったんだ。もっと早くこのページを知っていればよかった!興味がある人は、アプリはこちらだよ: https://apps.apple.com/app/apple-store/id6475267297?pt=11914...

こんなに設定しても、RustやGolangより効率が悪いのは変わらない。だから、多くのエンジニアがJVMのオプションを調整するのに時間を無駄にして、結局は「スケール」するために何百ものマイクロサービスを複製してAWSでお金を失ってる。技術の問題(Java)を認めたくないから、AWSは非効率で高価な技術を使う顧客が大好きなんだよね。それに、GoやRustは、どんなオプションの組み合わせでもJVMを圧倒してる。

確かに、_効率_の非常に狭い定義ではそうだけど。JVMやJavaに関して不満はたくさんあるけど、パフォーマンス、つまりドルあたりの作業量に関してはそれに当てはまらないよ。JITは生成されたコードを最適化する機会が多すぎるからね。

どんなツールがあっても、Rustはアセンブラより効率が悪いよ。

俺は昔はJavaの熱狂的なファンだったけど、ここ5年でRustを使うようになって、どんどん同意せざるを得なくなってる。でも、悲しいことに巨大なJavaの企業コードベースがまだ俺の生活を支えてくれてるから、どうしても付き合わなきゃいけないんだ。仕方ないよね。それに、パイプラインとかも、彼らは計算資源の無駄を楽しんでるみたいだし。

いや、ちょっと疑うな。最近、Pythonの友達がめちゃくちゃなPythonバックエンドを使ってたんだけど、Javaの方が速いって信じられなかったみたい。でも、数字は嘘をつかないよ。浮動小数点を足すのを10億回やったら、Javaでは数秒で終わった。

それ、いいソースだね。どこから引っ張ってきたの?GoのGCは本当にひどくて、非決定的なポーズや致命的なレイテンシスパイクを引き起こすんだ。特にメモリの圧力と容量が高いときにね。256GBのヒープにGoのGCをぶつけてみな、どれだけ耐えられるか見てみて。技術には強みと弱みがある。Goの強みは、小さくて特化したソフトウェアを作ることと、バイナリの66%が「if err != nil return err」っていう部分だよ。Rustの強みは、C++って言わずにシンボルを持てるところで、5つのArcを使っただけで、ソフトウェアを3回も書き直したのに、少なくともクソみたいなCのfgets()をホットループの真ん中で使うよりは速く動くって感じ。Javaは、スプリングブートを立ち上げて、リフレクションで文字列をインスタンス化できるから、なんでそうしないって感じだよ。Rustでもメモリをたくさん使うFizzBuzzEnterpriseFactoryFactoriesを書けるって約束するよ。

なんでJavaだけがヒープを慎重に調整しなきゃいけないのか、いまだに理解できない。最初にメモリを占有して、一定量を超えるとクラッシュするし、GCしてもOSにメモリを返さない。PythonやJSにはそんな問題ないのに。

「最近は大聖堂を建てないって言われてるけど、これがあるじゃん。JVMは現代の大聖堂だよ。」

何世代ものビルダーが壮大な計画のために協力してるけど、何世代もの~~王~~数十億ドルの企業に邪魔されて、GCのポーズのタイミングを正確にコントロールするために、また新しいフラグを追加してくれって言われる。実際、うちのサーバーは午前3時から3時半の間にしかGCできないことがわかったからね。

彼の別のプロジェクト「Byte Me」と、賢いjavapの使い方が、JVMバイトコードを学ぶのにすごく役立った。機械学習モデルコンパイラをJVM用に作るためにね(基本的にMLモデルをネイティブコードとしてコンパイルする;ONNX、ツリーアンサンブル、回帰器、分類器などをネイティブJVMクラスとして、巨大なランタイムなしで)。まだ進行中だけど、興味がある人のためにここにあるよ:Petrify: https://github.com/exabrial/petrify

なぜバイトコードじゃなくてJavaのソースコードにコンパイルしないの?ユーザーは自分のJavaコンパイラを使えるし。ANTLRがいろんなテキストをASTにパースするためのコードを生成するのと同じ感じだね。

Chromeには今日現在1496の[0]既知のオプションがあるけど、もう少しプッシュしたらJVMの1843に追いつくかもね。上のようなインターフェースで物事を整理できると、かなり役立つと思うよ。[0] https://peter.sh/experiments/chromium-command-line-switches/

なぜバイトコードじゃなくてJavaのソースコードにコンパイルしないの?ユーザーは自分のJavaコンパイラを使えるし。ANTLRがいろんなテキストをASTにパースするためのコードを生成するのと同じ感じだね。

上のボタンは全く別のドメインにリンクしてるけど、同じページを表示してる。だから、複数のドメインがある一つのページって感じで、一つのドメインに複数のページがあるわけじゃないんだ。

じゃあ、全部一気に動かしてみてよ!(コンフリクトが多いのは分かってるし、全部を扱えるシェルバッファなんてないけど) 冗談はさておき、オプションが何千もあるのを見たときは「うわ、マジか」と思ったよ。もっとオプションが多い公開プログラムってあるの?

現代のJVMはシェルバッファの問題に対する解決策を持ってるよ :D そのオプションをファイルに書き込んで、JVMに@を使って読み込ませることができるんだ。例えば、java @all-options.txt -jar my.jarみたいにね。