LoginSignup
3
0

More than 3 years have passed since last update.

Oracle PGXでjava.lang.OutOfMemoryErrorが発生した時の3つの対処法

Last updated at Posted at 2019-09-01

記事を書いた理由

Oracle PGXでOutOfMemoryErrorが発生した際、対処に土日を費やしてしまったため、対処法を備忘録として残しておきます。

発生したエラー

DeepWalk、Pg2vecというアルゴリズムを動かそうとしている時、以下のエラーが発生しました。

pgx> graph=session.readGraphWithProperties("NCI109.json").undirect() #Load Data
==> PgxGraph[name=sub-graph_1,N=122494,E=265202,created=1567303434267]
pgx> model=analyst.deepWalkModelBuilder()\ #Create Model
..1>   .setWindowSize(3)\
..2>   .setWalksPerVertex(6)\
..3>   .setWalkLength(4)\
..4>   .build()
==> oracle.pgx.api.beta.mllib.DeepWalkModel@2abbd0d9
pgx> model.fit(graph) #Training
ERROR: java.lang.OutOfMemoryError: Cannot allocate new FloatPointer(24403600): totalBytes = 338M, physicalBytes = 955M
pgx> graph=session.readGraphWithProperties("NCI109.json").undirect() #Load Data
==> PgxGraph[name=sub-graph_1,N=122494,E=265202,created=1567303434267]
pgx> model = analyst.pg2vecModelBuilder()\  #Training
..1>         .setGraphLetIdPropertyName("graph_id")\
..2>         .setVertexPropertyNames(Arrays.asList("node_label"))\
..3>         .setWindowSize(4)\
..4>         .setWalksPerVertex(5)\
..5>         .setWalkLength(8)\
..6>         .build()
==> oracle.pgx.api.beta.mllib.Pg2vecModel@5a936e64
pgx> model.fit(graph) #Training
ERROR: java.lang.OutOfMemoryError: Java heap space

PGXのメモリ構造

PGXのメモリには、大きく分けて2種類のメモリが存在します。グラフのトポロジーを読み込むメモリノードとエッジのプロパティーを読み込むメモリの2つです。

グラフのトポロジーを読み込むメモリ

ここには、グラフのトポロジー(プロパティーを考慮せず、各ノードと各エッジがどのように繋がっているかを表す情報)が読み込まれます。
PGXでは、グラフのトポロジーを格納するために、メモリの消費量を最小限に抑え、読み込み速度を最速化できる圧縮行格納方式(CSR : Compressed Sparse Row)を採用しています。
圧縮行格納方式に関しては、Wikipediaの解説がわかりやすいので、そちらをご参照ください。

プロパティーを読み込むメモリ

ここには、各ノードと各エッジのプロパティーが読み込まれます。

プロパティのメモリ消費量

Property Type Size in Bytes
int 4
float 4
long 8
double 8
boolean 1
date 8
local date 4
time 4
timestamp 8
time with timezone 8
timestamp with timezone 12
point 2d 16
string variable

Documentより引用

考えられる原因

OutOfMemoryErrorの原因として考えられるものは、以下の3つです。

  • On-heap領域が足りなくなったにも関わらず、PGXがメモリを獲得しようとしている
  • Off-heap領域が足りなくなったにも関わらず、PGXがメモリを獲得しようとしている
  • PGXで使用できるメモリ領域が少ない(OS上で設定されている)

これらは、ログを見ることで解析することができます。
PGXで詳細なログを見る場合は、以下のコマンドを実行します。

pgx> :ll root debug
==> log level of root logger set to DEBUG

その他にも、様々なログレベルを設定することができます。詳細は、Documentを参照してください。

対処法:On-heap領域が足りなくなった場合

On-heap領域が足りなくなった場合は、単純にPGXに割り当てるヒープ領域を増やします。

ローカルでJavaアプリケーションとしてPGXを実行している場合

アプリケーション起動時に、以下のオプションを設定します。

例)ヒープ領域の初期サイズを1024MB、最大サイズを2048MBに設定する

java -Xms1024m -Xmx2048m メインクラス名

PGXシェルでPGXを実行している場合

環境変数JAVA_OPTSを設定してから、再度PGXを起動します。

例)ヒープ領域の初期サイズを1024MB、最大サイズを2048MBに設定する

export JAVA_OPTS="-Xms1024m -Xmx2048m"
echo $JAVA_OPTS
-Xms1024m -Xmx2048m
sh $PGX_HOME/bin/pgx

対処法:Off-heap領域が足りなくなった場合

pgx.conf内のmax_off_heap_sizeを確認します。
(max_off_heap_sizeは、新たなメモリ領域の獲得をしなくなるための、単なる閾値です。もともと設定されていても、設定されていた値以上にメモリが獲得されることもあります。)

vi $PGX_HOME/conf/pgx.conf
{
  "allow_idle_timeout_overwrite": true,
  "allow_local_filesystem": false,
  "allow_task_timeout_overwrite": true,
  "enable_gm_compiler": true,
  "max_off_heap_size":1024,  #これを無くしてみる
  "enterprise_scheduler_config": {
    "analysis_task_config": {
      "priority": "MEDIUM",
      "weight": "<no-of-CPUs>",
      "max_threads": "<no-of-CPUs>"
    },
    "fast_analysis_task_config": {
      "priority": "HIGH",
      "weight": 1,
      "max_threads": "<no-of-CPUs>"
    },
    "num_io_threads_per_task": "<no-of-CPUs>"
  },
  "graphs": [],
  "max_active_sessions": 1024,
  "max_queue_size_per_session": -1,
  "max_snapshot_count": 0,
  "memory_cleanup_interval": 600,
  "path_to_gm_compiler": null,
  "release_memory_threshold": 0.85,
  "session_idle_timeout_secs": 0,
  "session_task_timeout_secs": 0,
  "strict_mode": true,
  "tmp_dir": "tmp_data",
  "in_place_update_consistency_model" : "ALLOW_INCONSISTENCIES"
}

対処法:PGXで使用できるメモリ領域が少ない場合

上記2つの方法を試してもうまくいかない場合は、PGXで使用できるメモリ領域が少ないことを疑いましょう。
(今回は、この方法を試してうまくいくようになりました。)
その場合は、OS上でメモリ割り当てを増やしてあげます。
私はDockerを使用してPGXを動かしているのですが、どうも割り当てられているメモリ容量が小さいように感じました。

今までは見逃していたのですが、PGX起動時に、割り当てられたメモリの総量を確認すると、1999MBしか割り当てられていないことがわかりました。

Kohei:NCI109 kohei$ pgx
tput: unknown terminfo capability 'setafsd'
[WARNING] PGX shell is using Groovy installed in /opt/groovy-2.5.8. It is the responsibility of the user to use the latest version of Groovy and to protect against known Groovy vulnerabilities.
[WARNING] The Groovy-based PGX shell will be removed and replaced by a jshell-based PGX shell.
Sep 01, 2019 1:56:34 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
01:56:36,187 INFO Ctrl$1 - >>> start engine
01:56:37,070 INFO StartupLogging - >>> PGX sm engine 19.2.1/ API 3.4.1 running.
01:56:37,071 INFO StartupLogging - >>> PGQL version 1.2
01:56:37,072 INFO StartupLogging - >>> Built from commit fdc975ef0f19828115fd76ed19ca79c45af52d2e
01:56:37,072 INFO StartupLogging - >>> Built at 2019-06-27T09:38:59.982-07:00
01:56:37,073 INFO StartupLogging - >>> JDK version: 1.8.0_212
01:56:37,073 INFO StartupLogging - >>> Operating system: Linux
01:56:37,074 INFO StartupLogging - >>> Number of processors: 2
01:56:37,076 INFO StartupLogging - >>> Total system memory: 1999 MB #これを増やしたい!

PGX Shell 19.2.1
PGX server version: 19.2.1 type: SM running in embedded mode.
PGX server API version: 3.4.1
PGQL version: 1.2
type :help for available commands
variables instance, session and analyst ready to use
pgx> 

Dockerのメモリを増やす

ということで、Dockerが使用できるメモリを増やします。

  1. クジラのマークをクリックします(充電しろよ、というツッコミは無視します)。
    スクリーンショット 2019-09-01 16.50.22.png

  2. Preferencesをクリックします。
    スクリーンショット 2019-09-01 16.53.42.png

  3. Advancedタブを選択し、割り当てたいメモリ量を調整します。
    スクリーンショット 2019-09-01 16.55.19.png

  4. Apply & Restartをクリックし、Dockerが再起動するのを待ちます。
    スクリーンショット 2019-09-01 16.57.26.png

  5. Dockerが再起動したら、再度PGXを起動します。

kohei$ pgx
tput: unknown terminfo capability 'setafsd'
[WARNING] PGX shell is using Groovy installed in /opt/groovy-2.5.8. It is the responsibility of the user to use the latest version of Groovy and to protect against known Groovy vulnerabilities.
[WARNING] The Groovy-based PGX shell will be removed and replaced by a jshell-based PGX shell.
Sep 01, 2019 7:58:52 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
07:58:55,010 INFO Ctrl$1 - >>> start engine
07:58:56,168 INFO StartupLogging - >>> PGX sm engine 19.2.1/ API 3.4.1 running.
07:58:56,173 INFO StartupLogging - >>> PGQL version 1.2
07:58:56,173 INFO StartupLogging - >>> Built from commit fdc975ef0f19828115fd76ed19ca79c45af52d2e
07:58:56,174 INFO StartupLogging - >>> Built at 2019-06-27T09:38:59.982-07:00
07:58:56,178 INFO StartupLogging - >>> JDK version: 1.8.0_212
07:58:56,178 INFO StartupLogging - >>> Operating system: Linux
07:58:56,180 INFO StartupLogging - >>> Number of processors: 2
07:58:56,185 INFO StartupLogging - >>> Total system memory: 5453 MB  #1999MBから増加した!

PGX Shell 19.2.1
PGX server version: 19.2.1 type: SM running in embedded mode.
PGX server API version: 3.4.1
PGQL version: 1.2
type :help for available commands
variables instance, session and analyst ready to use
pgx> 

メモリ容量が増えました!早速実行します!

DeepWalk

pgx> graph=session.readGraphWithProperties("NCI109.json").undirect()
==> PgxGraph[name=sub-graph_1,N=122494,E=265202,created=1567324836478]
pgx> model=analyst.deepWalkModelBuilder()\
..1> .setWindowSize(3)\
..2> .setWalksPerVertex(6)\
..3> 
..3> .setWalkLength(4)\
..4> .build()
==> null
pgx> model.getLoss() #学習後の損失を算出する
==> -2.85346752548799
pgx> sim=model.computeSimilars(111,3) #ID111のノードと似ているノードを3つ見つける
==> oracle.pgx.api.beta.frames.internal.PgxFrameImpl@bf75b5c
pgx> sim.print()
+--------------------------------+
| dstVertex | similarity         |
+--------------------------------+
| 111       | 1.0000001192092896 |
| 85        | 0.9343633055686951 |
| 81        | 0.8769448399543762 |
+--------------------------------+
==> oracle.pgx.api.beta.frames.internal.PgxFrameImpl@bf75b5c

Pg2vec

pgx> graph=session.readGraphWithProperties("NCI109.json").undirect()
==> PgxGraph[name=sub-graph_1,N=122494,E=265202,created=1567325544948]
pgx> model = analyst.pg2vecModelBuilder()\
..1>        .setGraphLetIdPropertyName("graph_id")\
..2>        .setVertexPropertyNames(Arrays.asList("node_label"))\
..3>        .setWindowSize(4)\
..4>        .setWalksPerVertex(5)\
..5>        .setWalkLength(8)\
..6>        .build()
==> oracle.pgx.api.beta.mllib.Pg2vecModel@1727e03a
pgx> model.fit(graph)
==> null
pgx> similars = model.computeSimilars(52, 10) #ID52のグラフレットと似ているグラフレットを10個見つける
==> oracle.pgx.api.beta.frames.internal.PgxFrameImpl@78d71df1
pgx> similars.print()
+----------------------------------+
| dstGraphlet | similarity         |
+----------------------------------+
| 52          | 1.0                |
| 42          | 0.8582297563552856 |
| 49          | 0.8517727255821228 |
| 74          | 0.8314518332481384 |
| 483         | 0.8259901404380798 |
| 48          | 0.8057224154472351 |
| 102         | 0.7991676330566406 |
| 73          | 0.7878939509391785 |
| 55          | 0.7401301860809326 |
| 381         | 0.7370997071266174 |
+----------------------------------+
==> oracle.pgx.api.beta.frames.internal.PgxFrameImpl@78d71df1

動くようになりました!

まとめ

PGXでOutOfMemoryErrorが発生したら、まずは以下の3つの方法を順に試すべきです。
詳しくはDocumentにも記載されているので、ご参照ください。

  • On-heap領域を増やす
  • Off-heap領域を増やす
  • PGXで使用できるメモリ領域を増やす
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0