You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否通过Python获取进程线程信息?需线程名、内存占用等数据

获取进程线程的名称与内存消耗

是的,可以通过Python获取线程名称和内存消耗数据,psutil本身没封装这些功能,需要结合平台特定的API或系统文件来实现:

一、获取线程名称

Linux 平台

Linux的/proc文件系统直接暴露了线程的名称,位于/proc/<pid>/task/<tid>/comm路径下,读取这个文件就能得到线程名称:

import psutil

def get_thread_names(pid):
    thread_names = {}
    proc = psutil.Process(pid)
    for thread in proc.threads():
        tid = thread.id
        try:
            with open(f"/proc/{pid}/task/{tid}/comm", "r") as f:
                thread_names[tid] = f.read().strip()
        except FileNotFoundError:
            thread_names[tid] = "unknown"
    return thread_names

# 示例:获取当前进程的线程名称
current_pid = psutil.Process().pid
print(get_thread_names(current_pid))

Windows 平台

Windows 10 1607及以上版本可以通过kernel32.dll的GetThreadDescription函数获取线程名称,需要用ctypes调用系统API:

import psutil
import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

# 定义系统函数的参数和返回值类型
kernel32.OpenThread.argtypes = (wintypes.DWORD, wintypes.BOOL, wintypes.DWORD)
kernel32.OpenThread.restype = wintypes.HANDLE

kernel32.GetThreadDescription.argtypes = (wintypes.HANDLE, ctypes.POINTER(wintypes.LPWSTR))
kernel32.GetThreadDescription.restype = wintypes.HRESULT

kernel32.CloseHandle.argtypes = (wintypes.HANDLE,)
kernel32.CloseHandle.restype = wintypes.BOOL

def get_thread_names_windows(pid):
    thread_names = {}
    proc = psutil.Process(pid)
    for thread in proc.threads():
        tid = thread.id
        # 打开线程,需要THREAD_QUERY_LIMITED_INFORMATION权限
        h_thread = kernel32.OpenThread(0x0800, False, tid)
        if not h_thread:
            thread_names[tid] = "unknown"
            continue
        
        name_ptr = wintypes.LPWSTR()
        if kernel32.GetThreadDescription(h_thread, ctypes.byref(name_ptr)) == 0:  # S_OK
            thread_names[tid] = name_ptr.value
            kernel32.LocalFree(name_ptr)
        else:
            thread_names[tid] = "unknown"
        
        kernel32.CloseHandle(h_thread)
    return thread_names

# 示例:获取当前进程的线程名称
current_pid = psutil.Process().pid
print(get_thread_names_windows(current_pid))

二、获取线程内存消耗

线程的内存主要包括栈内存和线程本地存储(TLS),不同平台的获取方式不同:

Linux 平台

通过/proc/<pid>/task/<tid>/status文件可以读取线程的栈内存(VmStk字段)和TLS相关内存(VmData字段):

import psutil

def get_thread_memory_linux(pid):
    thread_memory = {}
    proc = psutil.Process(pid)
    for thread in proc.threads():
        tid = thread.id
        mem_info = {"stack_memory": "unknown", "tls_memory": "unknown"}
        try:
            with open(f"/proc/{pid}/task/{tid}/status", "r") as f:
                for line in f:
                    if line.startswith("VmStk:"):
                        mem_info["stack_memory"] = f"{line.split()[1]} {line.split()[2]}"
                    elif line.startswith("VmData:"):
                        mem_info["tls_memory"] = f"{line.split()[1]} {line.split()[2]}"
            thread_memory[tid] = mem_info
        except FileNotFoundError:
            thread_memory[tid] = mem_info
    return thread_memory

# 示例:获取当前进程的线程内存信息
current_pid = psutil.Process().pid
print(get_thread_memory_linux(current_pid))

Windows 平台

Windows没有直接获取线程内存的简单API,需要通过VirtualQueryEx遍历线程栈区域来计算栈内存大小,示例如下:

import psutil
import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

# 定义系统函数和数据结构
kernel32.OpenProcess.argtypes = (wintypes.DWORD, wintypes.BOOL, wintypes.DWORD)
kernel32.OpenProcess.restype = wintypes.HANDLE

kernel32.OpenThread.argtypes = (wintypes.DWORD, wintypes.BOOL, wintypes.DWORD)
kernel32.OpenThread.restype = wintypes.HANDLE

kernel32.GetThreadContext.argtypes = (wintypes.HANDLE, ctypes.POINTER(ctypes.c_void_p))
kernel32.GetThreadContext.restype = wintypes.BOOL

kernel32.CloseHandle.argtypes = (wintypes.HANDLE,)
kernel32.CloseHandle.restype = wintypes.BOOL

class MEMORY_BASIC_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("BaseAddress", wintypes.LPVOID),
        ("AllocationBase", wintypes.LPVOID),
        ("AllocationProtect", wintypes.DWORD),
        ("RegionSize", wintypes.SIZE_T),
        ("State", wintypes.DWORD),
        ("Protect", wintypes.DWORD),
        ("Type", wintypes.DWORD)
    ]

kernel32.VirtualQueryEx.argtypes = (wintypes.HANDLE, wintypes.LPCVOID, ctypes.POINTER(MEMORY_BASIC_INFORMATION), wintypes.SIZE_T)
kernel32.VirtualQueryEx.restype = wintypes.SIZE_T

def get_thread_stack_memory_windows(pid):
    thread_stack = {}
    # 打开进程,需要PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限
    h_process = kernel32.OpenProcess(0x0400 | 0x0010, False, pid)
    if not h_process:
        return thread_stack
    
    proc = psutil.Process(pid)
    for thread in proc.threads():
        tid = thread.id
        # 打开线程,需要THREAD_GET_CONTEXT权限
        h_thread = kernel32.OpenThread(0x0010, False, tid)
        if not h_thread:
            thread_stack[tid] = "unknown"
            continue
        
        # 获取线程上下文,获取栈指针
        class CONTEXT(ctypes.Structure):
            _fields_ = [("Esp", wintypes.DWORD)] if ctypes.sizeof(ctypes.c_void_p) == 4 else [("Rsp", wintypes.DWORD64)]
        
        context = CONTEXT()
        if kernel32.GetThreadContext(h_thread, ctypes.byref(context)):
            stack_ptr = context.Esp if ctypes.sizeof(ctypes.c_void_p) ==4 else context.Rsp
            total_size = 0
            current_ptr = stack_ptr
            
            while True:
                mbi = MEMORY_BASIC_INFORMATION()
                size = kernel32.VirtualQueryEx(h_process, wintypes.LPCVOID(current_ptr), ctypes.byref(mbi), ctypes.sizeof(mbi))
                if size ==0:
                    break
                # 检查是否是已提交的栈区域
                if mbi.State == 0x1000 and (mbi.Protect & 0x04):  # MEM_COMMIT | PAGE_READWRITE
                    total_size += mbi.RegionSize
                    current_ptr = ctypes.cast(mbi.BaseAddress, wintypes.LPVOID).value + mbi.RegionSize
                else:
                    break
            thread_stack[tid] = f"{total_size / 1024:.2f} KB"
        else:
            thread_stack[tid] = "unknown"
        
        kernel32.CloseHandle(h_thread)
    
    kernel32.CloseHandle(h_process)
    return thread_stack

# 示例:获取当前进程的线程栈内存
current_pid = psutil.Process().pid
print(get_thread_stack_memory_windows(current_pid))

注意:线程内存数据是近似值,因为进程的大部分内存是线程共享的,线程仅占用栈、TLS等私有内存区域。

内容的提问来源于stack exchange,提问作者ali khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 07:05:50