Skip Navigation
Show nav
Dev Center
  • Get Started
  • ドキュメント
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • ドキュメント
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku のアーキテクチャ
    • Dyno (アプリコンテナ)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • スタック (オペレーティングシステムイメージ)
    • ネットワーキングと DNS
    • プラットフォームポリシー
    • プラットフォームの原則
  • Developer Tools
    • コマンドライン
    • Heroku VS Code Extension
  • デプロイ
    • Git を使用したデプロイ
    • Docker によるデプロイ
    • デプロイ統合
  • 継続的デリバリーとインテグレーション
    • 継続的統合
  • 言語サポート
    • Node.js
      • Working with Node.js
      • Node.js Behavior in Heroku
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails のサポート
      • Bundler の使用
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Python でのバックグランドジョブ
      • Python Behavior in Heroku
      • Django の使用
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Maven の使用
      • Spring Boot の使用
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go の依存関係管理
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • データベースとデータ管理
    • Heroku Postgres
      • Postgres の基礎
      • Postgres スターターガイド
      • Postgres のパフォーマンス
      • Postgres のデータ転送と保持
      • Postgres の可用性
      • Postgres の特別なトピック
      • Migrating to Heroku Postgres
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • その他のデータストア
  • AI
    • Working with AI
    • Heroku Inference
      • Inference API
      • Quick Start Guides
      • AI Models
      • Inference Essentials
    • Vector Database
    • Model Context Protocol
  • モニタリングとメトリクス
    • ログ記録
  • アプリのパフォーマンス
  • アドオン
    • すべてのアドオン
  • 共同作業
  • セキュリティ
    • アプリのセキュリティ
    • ID と認証
      • シングルサインオン (SSO)
    • Private Space
      • インフラストラクチャネットワーキング
    • コンプライアンス
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Team
    • Heroku Connect (Salesforce 同期)
      • Heroku Connect の管理
      • Heroku Connect のリファレンス
      • Heroku Connect のトラブルシューティング
  • パターンとベストプラクティス
  • Heroku の拡張
    • Platform API
    • アプリの Webhook
    • Heroku Labs
    • アドオンのビルド
      • アドオン開発のタスク
      • アドオン API
      • アドオンのガイドラインと要件
    • CLI プラグインのビルド
    • 開発ビルドパック
    • Dev Center
  • アカウントと請求
  • トラブルシューティングとサポート
  • Salesforce とのインテグレーション
  • 言語サポート
  • Java
  • Troubleshooting Java Apps
  • Java アプリケーションでのメモリ問題のトラブルシューティング

Java アプリケーションでのメモリ問題のトラブルシューティング

日本語 — Switch to English

この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。

最終更新日 2024年01月18日(木)

Table of Contents

  • JVM メモリ使用量
  • コンテナ内で実行するための Java の設定
  • Java アプリケーションのメモリ使用のプロファイリング
  • Heroku のメモリ制限
  • Heroku での Java アプリケーションのプロファイリング
  • Heroku 上で実行するためのメモリのヒント

アプリケーションのメモリ使用量を調整するには、Java がメモリをどのように使用するのか、およびアプリケーションのメモリ使用をどのように可視化できるかの両方を理解する必要があります。

JVM メモリ使用量

JVM はさまざまな方法でメモリを使用します。メモリは主にヒープ​として使用されますが、これだけではありません。メモリはヒープ以外に、Metaspace​やスタック​によっても使用されます。

Java ヒープ​ - ヒープとは、クラスのインスタンス (あるいはオブジェクト​) が保管される場所です。インスタンス変数はオブジェクトに保管されます。Java のメモリおよび最適化について議論するとき、ほとんどの場合はヒープについての議論となります。これは、ヒープはユーザーによってほぼ制御でき、この場所でガベージコレクション (および GC 最適化) が実行されるためです。ヒープサイズは -Xms​ および -Xmx​ の JVM フラグで制御されます。詳しくは、GC and The Heap​ (GC およびヒープ) を参照してください。

Java スタック​ - 各スレッドには独自のコールスタックがあります。スタックにはプリミティブ型のローカル変数とオブジェクト参照のほか、コールスタック (メソッド呼び出し) 自体も格納されています。スタックはスタックフレームがコンテキストを離れるとクリーンアップされるため、ここでは GC は実行されません。-Xss​JVM オプションは、スレッドのスタックごとに割り当てられるメモリの量を制御します。

Metaspace​ - Metaspace は、オブジェクトのクラス定義を保管します。Metaspace のサイズは -XX:MetaspaceSize​ を設定して制御します。

追加の JVM オーバーヘッド​ - 上記に加えて、一部のメモリが JVM 自体によって消費されます。これは JVM 用の C ライブラリと、残りのメモリプールを実行するために使用する一部の C メモリ割り当てオーバーヘッドを保持します。JVM 上で実行する可視性ツールはこのオーバーヘッドを表示しないため、アプリケーションがメモリを使用する方法についての概念を示すことはできますが、JVM プロセッサの合計メモリ使用量を表示することはできません。この種類のメモリは、glibc メモリ動作の調整​による影響を受けることがあります。

コンテナ内で実行するための Java の設定

JVM は、使用可能なオペレーティングシステムレポートに基づき、さまざまなメモリカテゴリのデフォルト割り当て値を設定しようとします。ただし、コンテナ (Heroku の dyno​ や Docker コンテナなど) の内部で実行するとき、OS によって報告される値が正しくないことがあります。これは、cgroup​ メモリ制限を代わりに使用するよう JVM を設定することによって回避できます。

Java 8 では、cgroup メモリ制限の使用は試験的な機能であり、次のオプションを (Procfile​ 内または環境変数のいずれかで) JVM プロセスに追加することによって有効化できます。

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

Java 9 以降では、このオプションは試験的なものではなくなりました。

-XX:+UseContainerSupport

これらのオプションは JVM プロセスの全体的なメモリフットプリントを減少させることがあります。そうならない場合、別の調整を行う前に、JVM がメモリを使用する方法を調査する必要があります。

Java アプリケーションのメモリ使用のプロファイリング

アプリケーションが開発環境と本番環境の両方でメモリを使用する方法を理解することは重要です。メモリの問題の大半は、あまり手間をかけずにあらゆる環境で再現できます。通常はメモリの問題をローカルマシンでトラブルシューティングする方が簡単です。これは、多くのツールにアクセスでき、監視ツールが引き起こす可能性がある副作用について心配しなくて済むためです。

Java アプリケーションのメモリ使用について洞察を得るために使用できるツールはいくつか存在します。一部のツールは Java ランタイム自体にパッケージ化されており、開発マシンにすでに存在しています。サードパーティから入手できるものもあります。ここでは網羅的なリストを示すつもりはなく、これらのツールを検討する上での出発点を示しているにすぎません。

Java ランタイムに付属するツールとしては、jmap​ (ヒープダンプの実行とメモリ統計の収集)、jstack​ (あらゆる時点での実行中のスレッドの検査)、jstat​ (一般的な JVM 統計の収集)、および jhat​ (ヒープダンプの分析) などがあります。これらのツールの詳細については、Oracle Docs​ または IBM developer works​ を参照してください。

Heroku アプリケーション関連の指標​は、ヒープおよびヒープ以外のメモリおよび GC アクティビティのグラフを提供します。この機能を使用可能にするための詳しい説明については、言語ランタイム関連の指標のドキュメント​を参照してください。

VisualVM​ は、上記のすべてのツールを、一部のユーザーにとって使いやすい GUI ベースのパッケージに組み合わせたものです。

YourKit​ は優れた市販のツールです。

Heroku のメモリ制限

アプリケーションで使用できる物理メモリの量は、dyno タイプ​によって異なります。アプリケーションではこれよりも多くのメモリを消費することができますが、dyno はディスクへのページングを開始します。これによってパフォーマンスが大きく損なわれるため、避けることが賢明です。このページングが発生し始めると、アプリケーションログに R14​ エラーが表示されます。

JVM ベースのほとんどの言語に対するデフォルトのサポートでは、dyno タイプ​に基づき、-Xss512k​ および Xmx​ を動的に設定します。これらのデフォルトにより、ほとんどのアプリケーションは R14 エラーを回避できます。デフォルトの完全なセットについては、Language Support Docs​ (言語サポートドキュメント) で、選択した言語およびフレームワークを参照してください。

Heroku での Java アプリケーションのプロファイリング

上記のプロファイリングツールの使用は Heroku のクラウド上では異なりますが、これはプラットフォームのプロセス分離モデルが原因です。ただし、Heroku の JVM 言語サポートでは、これらのツールを Heroku に接続する方法を簡素化するツールが提供されています。

このセクションに記載されているツールは、Heroku CLI 用の heroku-cli-java​ プラグインが必要です。次のようにしてインストールします。

$ heroku plugins:install heroku-cli-java

dyno へのプロファイリングツールの接続

Heroku Exec​ を使用して、多くの Java プロファイリングツールおよびデバッグツールを、Web dyno 内で実行中の JVM プロセスにアタッチできます。機能が有効化されると、スレッドダンプおよびヒープダンプを取得したり、JConsole や VisualVM などの一般的な GUI ベースのツールをアタッチしたりできます。たとえば、次のコードを実行できます。

$ heroku java:visualvm

これにより、web.1​ dyno に接続された VisualVM セッションが開始します。オプションとして、--dyno​ フラグを使用して、接続先の dyno を指定できます。

スレッドダンプの生成

Heroku Exec​ を有効化すると、dyno で実行中のアプリケーションプロセスのスレッドダンプを、次のコマンドを使用して生成できます。

$ heroku java:jstack

これにより、web.1​ dyno からのスレッドダンプがコンソールに出力されます。オプションで、ダンプの生成元となる dyno の名前を付けて --dyno​ フラグを指定することができます。

Heroku では jstack​ で -F​ オプションを使用することはできません。

ヒープダンプの生成

Heroku Exec​ を有効化すると、dyno で実行中のアプリケーションプロセスのヒープダンプを、次のコマンドを使用して生成できます。

$ heroku java:jmap

これにより、ヒープのヒストグラムが web.1​ dyno からコンソールに出力されます。オプションで、ダンプの生成元となる dyno の名前を付けた --dyno​ フラグを heroku java:jmap​ コマンドに指定することができます。HPROF 形式のバイナリヒープダンプが必要な場合、次のコマンドを実行できます。

$ heroku java:jmap --hprof

バイナリファイルは VisualVM、jhat​、Eclipse MAT​ などのツールを使用して後で分析できます。

高度な jmap​ オプションを使用する必要がある場合は、heroku ps:exec​ を実行して dyno へのシェルセッションを開始し、そこで jmap​ を実行します。バイナリヒープダンプを生成した場合、heroku ps:copy​ を実行することによって dyno の外部にこれをコピーできます。

Heroku では jmap​ で -F​ オプションを使用することはできません。

 

JRuby の場合は、heroku buildpacks:add -i 1 heroku/jvm​ を実行することによって、jvm-common​ を buildpack に明示的に追加する必要があります。

NativeMemoryTracking の設定

アプリのネイティブメモリ使用量が高レベルにある場合 (RSS の合計と JVM ヒープとの差など)、シャットダウン時にネイティブメモリ追跡情報を出力するようアプリケーションを設定することが必要な場合もあります。これを行うには、次の環境変数を設定します。

$ heroku config:set JAVA_OPTS="-XX:NativeMemoryTracking=detail -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics"

この設定により、次のコマンドを実行して One-off dyno 開始することによって、分離された環境内でメモリ使用をデバッグすることもできます。

$ heroku run bash

その後、Procfile​ コマンドの末尾に &​ を追加することによって、アプリプロセスをバックグラウンドで実行します。たとえば、次のようになります。

$ java -jar myapp.jar &

分離プロセスではなくライブプロセスにアタッチする場合、Heroku Exec を使用して、heroku ps:exec​ を実行することにより、実行中の Wed dyno を検査できます。

いずれの場合も、次のコマンドを実行することによって、Java プロセスのプロセス ID (PID) を取得できます。

$ jps
4 Main
105 Jps

この例では、PID は 4 です。ここで、jstack​、jmap​、jcmd​ などのツールをこのプロセスに対して使用することができます。たとえば、次のようになります。

$ jcmd 4 VM.native_memory summary
4:

Native Memory Tracking:

Total: reserved=1811283KB, committed=543735KB
-                 Java Heap (reserved=393216KB, committed=390656KB)
                            (mmap: reserved=393216KB, committed=390656KB)

-                     Class (reserved=1095741KB, committed=54165KB)
                            (classes #8590)
                            (malloc=10301KB #14097)
                            (mmap: reserved=1085440KB, committed=43864KB)

-                    Thread (reserved=22290KB, committed=22290KB)
                            (thread #30)
                            (stack: reserved=22132KB, committed=22132KB)
                            (malloc=92KB #155)
                            (arena=66KB #58)
...

jcmd​ を使用してネイティブメモリをデバッグすることの詳細については、ネイティブメモリトラッキングに関する Oracle のドキュメント​を参照してください。

アプリからのスレッドダンプの生成

アプリケーションコードからスレッドダンプを生成することもできます。これはプロセスの終了時にダンプの生成を試行するときに便利です。たとえば、次のようなコードを Java アプリケーションに追加することもできます。

Runtime.getRuntime().addShutdownHook(new Thread() {
  @Override
  public void run() {
    final java.lang.management.ThreadMXBean threadMXBean = java.lang.management.ManagementFactory.getThreadMXBean();
    final java.lang.management.ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100);
    for (java.lang.management.ThreadInfo threadInfo : threadInfos) {
      System.out.println(threadInfo.getThreadName());
      final Thread.State state = threadInfo.getThreadState();
      System.out.println("   java.lang.Thread.State: " + state);
      final StackTraceElement[] stackTraceElements = threadInfo.getStackTrace();
      for (final StackTraceElement stackTraceElement : stackTraceElements) {
        System.out.println("        at " + stackTraceElement);
      }
      System.out.println("\n");
    }
  }
});

あるいは Scala Play アプリケーションで、次の内容を持つ app/Global.scala​ ファイルを追加することができます。

object Global extends WithFilters() {
  override def onStop(app: Application) {
    var threadMXBean = java.lang.management.ManagementFactory.getThreadMXBean();
    var threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds, 100);
    threadInfos.foreach { threadInfo =>
      if (threadInfo != null) {
        println(s"""
'${threadInfo.getThreadName}': ${threadInfo.getThreadState}
  at ${threadInfo.getStackTrace.mkString("\n  at ")}
""")
      }
    }
  }
}

これらの例は両方とも、プロセスがシャットダウンするときにスレッド情報を stdout に出力します。このようにして、プロセスがデッドロックに陥った場合、次のようなコマンドでプロセスを再起動できます。

$ heroku ps:restart web.1

そしてスタック情報がログに表示されます。

冗長な GC フラグ

上記の情報が十分に詳細でない場合、GC 実行時に冗長な出力をログに取得するために使用できる JVM オプションもいくつか存在します。次のフラグを Java opts に追加します。-XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps

$ heroku config:set JAVA_OPTS='-Xss512k -XX:+UseCompressedOops -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps'
2012-07-07T04:27:59+00:00 app[web.2]: {Heap before GC invocations=43 (full 0):
2012-07-07T04:27:59+00:00 app[web.2]:  PSYoungGen      total 192768K, used 190896K [0x00000000f4000000, 0x0000000100000000, 0x0000000100000000)
2012-07-07T04:27:59+00:00 app[web.2]:   eden space 188800K, 100% used [0x00000000f4000000,0x00000000ff860000,0x00000000ff860000)
2012-07-07T04:27:59+00:00 app[web.2]:   from space 3968K, 52% used [0x00000000ffc20000,0x00000000ffe2c1e0,0x0000000100000000)
2012-07-07T04:27:59+00:00 app[web.2]:   to   space 3840K, 0% used [0x00000000ff860000,0x00000000ff860000,0x00000000ffc20000)
2012-07-07T04:27:59+00:00 app[web.2]:  ParOldGen       total 196608K, used 13900K [0x00000000e8000000, 0x00000000f4000000, 0x00000000f4000000)
2012-07-07T04:27:59+00:00 app[web.2]:   object space 196608K, 7% used [0x00000000e8000000,0x00000000e8d93070,0x00000000f4000000)
2012-07-07T04:27:59+00:00 app[web.2]:  PSPermGen       total 50816K, used 50735K [0x00000000dda00000, 0x00000000e0ba0000, 0x00000000e8000000)
2012-07-07T04:27:59+00:00 app[web.2]:   object space 50816K, 99% used [0x00000000dda00000,0x00000000e0b8bee0,0x00000000e0ba0000)
2012-07-07T04:27:59+00:00 app[web.2]: 2012-07-07T04:27:59.361+0000: [GC
2012-07-07T04:27:59+00:00 app[web.2]: Desired survivor size 3866624 bytes, new threshold 1 (max 15)
2012-07-07T04:27:59+00:00 app[web.2]:  [PSYoungGen: 190896K->2336K(192640K)] 204796K->16417K(389248K), 0.0058230 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2012-07-07T04:27:59+00:00 app[web.2]: Heap after GC invocations=43 (full 0):
2012-07-07T04:27:59+00:00 app[web.2]:  PSYoungGen      total 192640K, used 2336K [0x00000000f4000000, 0x0000000100000000, 0x0000000100000000)
2012-07-07T04:27:59+00:00 app[web.2]:   eden space 188800K, 0% used [0x00000000f4000000,0x00000000f4000000,0x00000000ff860000)
2012-07-07T04:27:59+00:00 app[web.2]:   from space 3840K, 60% used [0x00000000ff860000,0x00000000ffaa82d0,0x00000000ffc20000)
2012-07-07T04:27:59+00:00 app[web.2]:   to   space 3776K, 0% used [0x00000000ffc50000,0x00000000ffc50000,0x0000000100000000)
2012-07-07T04:27:59+00:00 app[web.2]:  ParOldGen       total 196608K, used 14080K [0x00000000e8000000, 0x00000000f4000000, 0x00000000f4000000)
2012-07-07T04:27:59+00:00 app[web.2]:   object space 196608K, 7% used [0x00000000e8000000,0x00000000e8dc0330,0x00000000f4000000)
2012-07-07T04:27:59+00:00 app[web.2]:  PSPermGen       total 50816K, used 50735K [0x00000000dda00000, 0x00000000e0ba0000, 0x00000000e8000000)
2012-07-07T04:27:59+00:00 app[web.2]:   object space 50816K, 99% used [0x00000000dda00000,0x00000000e0b8bee0,0x00000000e0ba0000)
2012-07-07T04:27:59+00:00 app[web.2]: }

Heroku Labs: log-runtime-metrics

Heroku Labs 機能に log-runtime-metrics​ と呼ばれるものがあります。これは合計メモリ使用量などの診断情報をアプリケーションログに出力します。

New Relic

一部の JVM 言語および Java フレームワークでは、New Relic​ Java エージェントを使用できます。

Heroku 上で実行するためのメモリのヒント

  • スレッドの使用とスタックサイズに注意してください。デフォルトオプション -Xss512k​ は、各スレッドが 512 KB のメモリを使用することを意味します。このオプションがない JVM のデフォルトは 1 MB です。
  • 重量級の監視エージェントに注意してください。一部の Java エージェントはそれ自体がメモリを著しく使用することがあり、問題のトラブルシューティングを試行するときにメモリの問題がさらに悪化することがあります。メモリの問題がある場合、エージェントを削除することが最初の一歩として適切です。上記のメモリロギングエージェントはメモリフットプリントが非常に小さいため、これらの問題を発生させません。

それでもなおメモリの問題が存在する場合は、Heroku Support​にいつでもご連絡ください。

関連カテゴリー

  • Troubleshooting Java Apps
JVM ランタイムメトリクス JVM ランタイムメトリクス

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices