心理学で、
人間関係を
ちょっとラクにする。
MBTIとアドラー心理学を軸に、
自分と他者を理解するヒントを発信しています。
何が起きたか
Ollama を launchd で常駐させてから、作業中に Mac の風切り音が急に大きくなり始めた。Activity Monitor を開くと ollama_llama_server が CPU 数十〜百数十% を常時食っている。モデルを使っていないのに、だ。「KeepAlive=true にしとけば楽」と思って設定した plist が、逆に Mac を常時フル稼働状態にしていた。これに気づくまで2日かかった。
環境
- macOS 15.4 Sequoia(MacBook Pro M5 32GB)
- Ollama 0.6.x(Homebrew インストール済み)
- qwen3.5:9b / gemma4:26b をメインモデルとして使用
- launchd plist を
~/Library/LaunchAgents/に配置 - 自動化スクリプト:
01_Scripts/lib/ai_client.py経由で各パイプラインが呼び出し
詰まったポイント
最初に疑ったのはスクリプト側だった。ai_client.py がループしてるとか、パイプラインが暴走してるとか。でも全部の Python プロセスを止めてもファンは回り続けた。
ps aux | grep ollama で確認すると、ollama_llama_server が生きていた。Ollama はモデルをリクエストされた瞬間にサーバープロセスを起動して、デフォルトで 5分間メモリに保持する仕様だ。問題はそこじゃなくて、保持が終わった後に launchd が即座にプロセスを再起動していたこと——これが原因だった。
KeepAlive=true は「プロセスが落ちたら即座に再起動する」という設定なので、Ollama がモデルをアンロードしてプロセスを終了しようとすると、launchd が黙って復活させる。その際にモデルの再ロードが走る。ループだ。
エラーログは特に出ない。/usr/local/var/log/ にも ~/Library/Logs/ にも何も残っていなかった。「正常に動いているけど重い」という状態で、デバッグの手がかりが掴みにくかった。
解決までの手順
ステップ1: まず現状の plist を確認する
cat ~/Library/LaunchAgents/com.taito.ollama.plist
この時点の中身は KeepAlive=true・RunAtLoad=true のシンプルな構成だった。モデルが自動アンロードされてプロセスが終了するたびに launchd が再起動する状態だった、という仮説がここで固まった。
ステップ2: OLLAMA_KEEP_ALIVE を短くセットして様子を見る
Ollama にはモデルの保持時間を制御する環境変数がある。デフォルトは 5m(5分)。まずこれを 0 にしてリクエスト直後に解放させてみた。
launchctl unload ~/Library/LaunchAgents/com.taito.ollama.plist
OLLAMA_KEEP_ALIVE=0 ollama serve &
CPU 使用率が下がった。モデルが即アンロードされてプロセスが静かになっている——という解釈でほぼ合ってると思う(推測を含む)。
ステップ3: KeepAlive を OnDemand 相当に切り替える
launchd の KeepAlive=true を削除して、RunAtLoad=false にした。これで Ollama は最初から起動しない。必要な時にスクリプト側から呼び出す構成に変える。
launchctl unload ~/Library/LaunchAgents/com.taito.ollama.plist
ステップ4: plist を書き直す
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.taito.ollama</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/ollama</string>
<string>serve</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>OLLAMA_KEEP_ALIVE</key>
<string>2m</string>
<key>OLLAMA_MAX_LOADED_MODELS</key>
<string>1</string>
<key>OLLAMA_NUM_PARALLEL</key>
<string>1</string>
</dict>
<key>RunAtLoad</key>
<false/>
<key>KeepAlive</key>
<false/>
<key>ThrottleInterval</key>
<integer>30</integer>
</dict>
</plist>
KeepAlive=false にしてプロセスが落ちたら落ちっぱなしにする。ThrottleInterval=30 は「再起動するなら30秒待て」というセーフガード。今回は KeepAlive を切ったので直接は効かないが、保険で残している。
ステップ5: スクリプト側で起動・停止を管理する
常駐させない分、使う前に Ollama が生きているか確認して、なければ起動する処理を ai_client.py の呼び出し前に入れた。
import subprocess
import time
import httpx
def ensure_ollama_running() -> bool:
try:
r = httpx.get("http://localhost:11434/api/tags", timeout=2)
return r.status_code == 200
except Exception:
pass
subprocess.Popen(
["ollama", "serve"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
for _ in range(10):
time.sleep(1)
try:
r = httpx.get("http://localhost:11434/api/tags", timeout=1)
if r.status_code == 200:
return True
except Exception:
continue
return False
ステップ6: 動作確認
再起動後、パイプラインを走らせながら Activity Monitor を確認。推論中は CPU が上がるが、完了後 2分で落ち着くようになった。ファンが止まった。
コード/設定の抜粋
上の plist で設定している環境変数を整理すると:
# 手動で確認する場合
OLLAMA_KEEP_ALIVE=2m \
OLLAMA_MAX_LOADED_MODELS=1 \
OLLAMA_NUM_PARALLEL=1 \
ollama serve
OLLAMA_MAX_LOADED_MODELS=1 は「同時にメモリに展開するモデルを1つに絞る」設定。qwen3.5:9b と gemma4:26b を混在させていたので、これがないと両方が展開されたままになる。32GB 共有メモリ環境だと地味に効く。
OLLAMA_NUM_PARALLEL=1 は同時処理リクエスト数の上限。パイプラインが並列で投げてくることがあるので、Mac のメモリプレッシャーが高まりやすいときの安全弁として入れている。
試してわかったこと
KeepAlive=true はサーバー用途のデーモン向けの設定で、Ollama みたいに「使うときだけ動く」モデルには相性が悪い。起動コストが高いプロセスを常駐させたい気持ちはわかるが、モデルのアンロード→再ロードのループを launchd が黙って引き起こす罠がある。
OLLAMA_KEEP_ALIVE の存在は公式ドキュメントに書いてあるけど、launchd との組み合わせで何が起きるかは書いていない。実際に詰まってみないと分からない類いの問題だった。
Apple Silicon の共有メモリアーキテクチャは GPU と CPU でメモリを共有しているので、モデルが展開されているだけで他のアプリへの影響が出やすい。「Ollama は軽い」という印象で使い始めると、この常駐コストに気づきにくい。
あと、エラーが出ない問題は本当に厄介だった。ログが空、プロセスは正常、でも Mac が重い——という状態だと、原因の切り分けに時間がかかる。ps aux と Activity Monitor を両方使いながら「どのプロセスがいつ何をしているか」を時系列で見るのが結局一番早かった。
まとめ
Ollama を launchd で常駐させるなら、KeepAlive=false + OLLAMA_KEEP_ALIVE=2m + OLLAMA_MAX_LOADED_MODELS=1 のセットが Apple Silicon Mac では現実的な設定だった。
常駐の利便性より、使わない時間のメモリ・CPU 解放を優先するほうが作業環境として安定する。
エラーが出ない重さこそが一番デバッグしにくいので、ps aux で状況を地道に観察することをお勧めする。✨
