pstackでプロセスフリーズを調査

ソフトウェア開発や運用において、プロセスがフリーズする状況に遭遇することがあります。この状況はシステムパフォーマンスの低下やサービス停止を引き起こす可能性があります。本稿では、pstackツールを使用してプロセスフリーズの問題をトラブルシューティングする方法について説明します。プロセスのスタック情報を分析することで、問題の原因を特定し解決策を見つけます。

風控システムの子サービスが応答停止し、風控サービスが利用不能に。サービス可用性モニタリングの不足により、プロセス応答停止をタイムリーに検知できず、システムが利用不能となった。

正文

プロセスデッドロックとは、プロセスが応答しなくなるものの、終了しない状態を指します。これは、デッドロック、リソース枯渇、例外など、様々な原因で発生する可能性があります。このような問題を解決するためには、pstackツールを使用してプロセスのスタック情報を分析し、問題の根本原因を特定することができます。

手順

pstack は、一般的に gdb(GNU デバッガー)と共に提供される便利なツールです。以下のコマンドでインストールできます。

sudo apt-get install gdb

プロセスIDの取得:まず、スリープ状態のプロセスのプロセスID(PID)を取得する必要があります。psコマンドを使用して、すべてのプロセスをリストし、調査対象のプロセスIDを見つけます。 pstack ツールを使用してプロセススタックを解析します。プロセス ID を取得したら、pstack ツールでそのプロセスのスタック情報を入手できます。以下のコマンドを実行してください:

pstack <PID>

このプロセスが実行中の関数呼び出しシーケンスを表示し、スタック情報を出力します。これらの情報から、プロセスの停止位置を特定し、問題の箇所を突き止めることができます。

スタック情報を解析することで、プロセスの応答なしの原因を特定できます。デッドロックや無限ループ、その他の異常が発見される可能性があります。状況に応じて、ロックの解放やコードロジックの修正などの対応策を講じてください。

事例

簡単なデモで、メイン関数起動後、新しいスレッドを作成し、実際の実行関数が無限ループに入り、プログラムが正常に終了せず、フリーズした状態になる。

cmake_minimum_required(VERSION 3.0.0)
project(pstack_main VERSION 0.1.0 LANGUAGES C CXX)

include(CTest)
enable_testing()

# 查找线程库
find_package(Threads REQUIRED)

add_executable(pstack_main main.cpp)

# 链接线程库
target_link_libraries(pstack_main PRIVATE Threads::Threads)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
#include <iostream>
#include <thread>
#include <chrono>

void infiniteLoop() {
    while (true) {
        // 主线程进入死循环
    }
}

int main() {
    std::thread thread(infiniteLoop); // 创建一个线程,执行死循环函数
    thread.join(); // 等待线程结束
    return 0;
}

プログラム起動、pstack結果:

Thread 2 (Thread 0x7eff3619b700 (LWP 1315017)):
#0  infiniteLoop () at /root/pstack/main.cpp:6
#1  0x0000000000402ca9 in std::__invoke_impl<void, void (*)()> (__f=@0x2260eb8: 0x4029a6 <infiniteLoop()>) at /usr/include/c++/8/bits/invoke.h:60
#2  0x0000000000402b02 in std::__invoke<void (*)()> (__fn=@0x2260eb8: 0x4029a6 <infiniteLoop()>) at /usr/include/c++/8/bits/invoke.h:95
#3  0x0000000000403150 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x2260eb8) at /usr/include/c++/8/thread:244
#4  0x0000000000403126 in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x2260eb8) at /usr/include/c++/8/thread:253
#5  0x000000000040310a in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x2260eb0) at /usr/include/c++/8/thread:196
#6  0x00007eff36bceb23 in execute_native_thread_routine () from /lib64/libstdc++.so.6
#7  0x00007eff36ea91ca in start_thread () from /lib64/libpthread.so.0
#8  0x00007eff361d58d3 in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x7eff372e1740 (LWP 1315016)):
#0  0x00007eff36eaa6cd in __pthread_timedjoin_ex () from /lib64/libpthread.so.0
#1  0x00007eff36bceda7 in std::thread::join() () from /lib64/libstdc++.so.6
#2  0x00000000004029d2 in main () at /root/pstack/main.cpp:13

確認できるところによると、プロセスのフリーズの原因は無限ループです。メインスレッドが無限ループに入り、サブスレッドが終了できず、結果としてプロセスがフリーズします。

Licensed under CC BY-NC-SA 4.0
最終更新 2025年05月28日 09:47
金融ITプログラマーのいじくり回しと日常のつぶやき
Hugo で構築されています。
テーマ StackJimmy によって設計されています。