3

我使用以下代码在 WinXPx32 上运行良好,但在 Win7x64 上返回 0。我知道 psutil 库也会返回它,但我需要一些可以在没有额外依赖项的情况下运行的东西,ctypes 和 win32api 很好。我也尝试过 Kernel32.K32GetProcessMemoryInfo ,结果相同。

import ctypes

psapi = ctypes.windll.psapi
Kernel32 = ctypes.windll.Kernel32

class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
    _fields_ = [("cb", ctypes.c_ulong),
                ("PageFaultCount", ctypes.c_ulong),
                ("PeakWorkingSetSize", ctypes.c_size_t),
                ("WorkingSetSize", ctypes.c_size_t),
                ("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
                ("QuotaPagedPoolUsage", ctypes.c_size_t),
                ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
                ("QuotaNonPagedPoolUsage", ctypes.c_size_t),
                ("PagefileUsage", ctypes.c_size_t),
                ("PeakPagefileUsage", ctypes.c_size_t),
                ("PrivateUsage", ctypes.c_size_t),
                ]

def GetProcessPrivateUsage():
    mem_struct = PROCESS_MEMORY_COUNTERS_EX()
    p_handle = Kernel32.GetCurrentProcess()
    b = psapi.GetProcessMemoryInfo(p_handle, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
    print(b)
    return mem_struct.PrivateUsage

print(GetProcessPrivateUsage())
4

2 回答 2

2

我怀疑问题是由于HANDLE在 64 位 Windows 上是 64 位,但在 32 位 Windows 上是 32 位。默认的 ctypes 返回类型是int,在两个系统上都是 32 位。有时它恰好可以工作,因为高 64 位恰好是正确的,但不能保证。

这与我们在SetHandleInformation没有显式参数和返回类型的情况下通过 ctypes 调用 CherryPy 时遇到的问题相同,我在此处进行了描述

您需要做的是明确指定您正在调用的 Win32 函数的argtypesrestype属性。这是processutil.py我为此制作的一个模块,它适用于 32 位和 64 位 Windows(我也将其作为ActiveState 配方上传):

"""Functions for getting memory usage of Windows processes."""

__all__ = ['get_current_process', 'get_memory_info', 'get_memory_usage']

import ctypes
from ctypes import wintypes

GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
GetCurrentProcess.argtypes = []
GetCurrentProcess.restype = wintypes.HANDLE

SIZE_T = ctypes.c_size_t

class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
    _fields_ = [
        ('cb', wintypes.DWORD),
        ('PageFaultCount', wintypes.DWORD),
        ('PeakWorkingSetSize', SIZE_T),
        ('WorkingSetSize', SIZE_T),
        ('QuotaPeakPagedPoolUsage', SIZE_T),
        ('QuotaPagedPoolUsage', SIZE_T),
        ('QuotaPeakNonPagedPoolUsage', SIZE_T),
        ('QuotaNonPagedPoolUsage', SIZE_T),
        ('PagefileUsage', SIZE_T),
        ('PeakPagefileUsage', SIZE_T),
        ('PrivateUsage', SIZE_T),
    ]

GetProcessMemoryInfo = ctypes.windll.psapi.GetProcessMemoryInfo
GetProcessMemoryInfo.argtypes = [
    wintypes.HANDLE,
    ctypes.POINTER(PROCESS_MEMORY_COUNTERS_EX),
    wintypes.DWORD,
]
GetProcessMemoryInfo.restype = wintypes.BOOL

def get_current_process():
    """Return handle to current process."""
    return GetCurrentProcess()

def get_memory_info(process=None):
    """Return Win32 process memory counters structure as a dict."""
    if process is None:
        process = get_current_process()
    counters = PROCESS_MEMORY_COUNTERS_EX()
    ret = GetProcessMemoryInfo(process, ctypes.byref(counters),
                               ctypes.sizeof(counters))
    if not ret:
        raise ctypes.WinError()
    info = dict((name, getattr(counters, name))
                for name, _ in counters._fields_)
    return info

def get_memory_usage(process=None):
    """Return this process's memory usage in bytes."""
    info = get_memory_info(process=process)
    return info['PrivateUsage']

if __name__ == '__main__':
    import pprint
    pprint.pprint(get_memory_info())
于 2013-04-25T01:27:40.387 回答
0

我根据MSDN中的以下示例修改了您的代码:

from __future__ import print_function
import ctypes

psapi = ctypes.windll.psapi
Kernel32 = ctypes.windll.Kernel32

PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010

class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
    _fields_ = [("cb", ctypes.c_ulong),
                ("PageFaultCount", ctypes.c_ulong),
                ("PeakWorkingSetSize", ctypes.c_size_t),
                ("WorkingSetSize", ctypes.c_size_t),
                ("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
                ("QuotaPagedPoolUsage", ctypes.c_size_t),
                ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
                ("QuotaNonPagedPoolUsage", ctypes.c_size_t),
                ("PagefileUsage", ctypes.c_size_t),
                ("PeakPagefileUsage", ctypes.c_size_t),
                ("PrivateUsage", ctypes.c_size_t),
                ]

def GetProcessPrivateUsage():
    mem_struct = PROCESS_MEMORY_COUNTERS_EX()

    id = Kernel32.GetCurrentProcessId()
    print_output('GetCurrentProcessId: {}'.format(id))

    handle = Kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, id)
    print_output('GetCurrentProcess: {}'.format(handle))

    b = psapi.GetProcessMemoryInfo(handle, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))

    print_output('GetProcessMemoryInfo: {}'.format(b))
    return mem_struct.PrivateUsage

def print_output(text):
    print('{}. {}'.format(text, ctypes.FormatError(Kernel32.GetLastError())))

usage = GetProcessPrivateUsage()
print_output('private usage: {}'.format(usage))

我最好的猜测是返回的句柄GetCurrentProcess()不再具有对 Windows 7 中内存计数器的访问权限(GetLastError()将返回“无效句柄”)。

我在 ctypes 中找不到PROCESS_QUERY_INFORMATIONand ,所以我在这里PROCESS_VM_READ查找了实际值并将它们作为常量插入。

我还添加了该print_output()功能,以便我可以查看哪些步骤失败了。

于 2012-07-26T14:55:03.240 回答