0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Godot の --headless --script は quit() を呼ばないと終わらない — 残ったプロセスがメモリを埋める

0
Last updated at Posted at 2026-11-08

はじめに

📝 この記事は note ・ Zenn にも投稿しています。

以前、Godot 4.6 で作っている RPG(kibi-kingdom)の動作確認を、AI にヘッドレス起動のテストスクリプトで回させていた。その途中で Mac のメモリが逼迫し、全プロセスを強制終了して再起動することになった。

原因は、テストを流すたびに起動した Godot が終わらずに居座っていたことだった。テストスクリプトは最後まで走り、結果も出力していた。止まっていなかったのは Godot のほうだった。

手元の Godot 4.6.3 で、同じ形を最小構成で再現した。

quit() の有無だけを変える

SceneTree を継承したスクリプトを --script で渡すと、シーンなしで GDScript を実行できる。違いは最後の quit() だけ。

# noquit.gd
extends SceneTree
func _init():
	print("test done")
# quit.gd
extends SceneTree
func _init():
	print("test done")
	quit()

空のプロジェクト(project.godot だけ)を置いたディレクトリで、それぞれ起動した。

G=/path/to/Godot.app/Contents/MacOS/Godot
$G --headless --path . --script quit.gd
# Godot Engine v4.6.3.stable.official.7d41c59c4 - https://godotengine.org
#
# test done
echo $?   # 0

quit.gd はすぐ終わる。noquit.gd は test done を出したあと、プロンプトに戻ってこない。

3回流すと3つ残る

テストを何度か流す状況に近づけて、noquit.gd をバックグラウンドで3回起動し、30秒後に見た。

for i in 1 2 3; do $G --headless --path . --script noquit.gd > n$i.log 2>&1 & done
sleep 30
ps -o pid=,etime=,rss=,command= -p $(pgrep -d, -f "Godot --headless")
94755 00:30 113744 .../Godot --headless --path . --script noquit.gd
94756 00:30 114048 .../Godot --headless --path . --script noquit.gd
94757 00:30 114224 .../Godot --headless --path . --script noquit.gd

3つとも生きていて、空のプロジェクトでも1つあたり約111MB。ログには test done が出ている。出力だけを見れば、テストは成功して終わったように見える。

ヘッドレスでも、Godot はメインループを回し続ける。_init() が終わっても、quit() を呼ぶまでエンジンは止まらない。今回は空のプロジェクトで測ったので、アセットを読み込む実プロジェクトの1つあたりの量は測っていない。テストを直しては流すのを繰り返すと、そのたびに1つずつ増えていく。

timeout で止めようとすると

外から時間を切ろうとして timeout を使うと、macOS の zsh には入っていない。

timeout 3 sleep 1
# zsh:1: command not found: timeout
echo $?   # 127

timeout が無いと Godot は起動されない。ただ、エラーを無視して先に進む書き方だと、テストが走っていないことに気づかないまま進んでしまう。Homebrew の coreutils を入れれば gtimeout が使えるが、手元には入っていなかった。

macOS に標準で入っている perl の alarm で代わりになった。

perl -e 'alarm shift; exec @ARGV' 5 $G --headless --path . --script noquit.gd
echo $?   # 142(SIGALRM で止まった・5秒)

止め方は3つ

  1. スクリプトの最後で quit() を呼ぶ。 失敗時に quit(1) を呼べば、終了コードが1になった(echo $? で確認)。合否を終了コードで取れる。
  2. 起動オプションで終わらせる。 --quit は1フレーム目のあとで終わる。--quit-after <フレーム数> で長さも指定できる。
$G --headless --path . --quit --script noquit.gd; echo $?
# 0(すぐ終わった)
$G --headless --path . --quit-after 60 --script noquit.gd; echo $?
# 0
  1. 後始末を必ず入れる。 途中で例外が出て quit() まで届かないこともあるので、流し終わったら残りを確かめて消す。
pkill -f "Godot --headless"
pgrep -fl Godot || echo none   # none

PID を覚えておいて kill するより、pkill -f でまとめて消すほうが取りこぼしがなかった。エディタで開いている Godot まで消さないように、--headless を条件に入れている。


テストの出力には "test done" と出ていた。終わったのはテストで、Godot ではなかった。

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?