在Windows中限制Python脚本的RAM使用量

8
我的程序根据使用情况可能会突然分配大量内存。我想限制它从系统中获取的内存。
我在这里看到: 将RAM使用限制为Python程序 但它只适用于Unix。有没有Windows的解决方案?

尝试将其与resource.RLIM_INFINITY结合使用了吗?https://docs.python.org/3/library/resource.html#resource.RLIM_INFINITY - Sharan Arumugam
与其限制您能够利用的内存量,我认为更好的做法是以不消耗系统资源的更高效方式执行所需的操作。升级硬件是最糟糕的可扩展性方案。 - Swift
@SharanArumugam 如我所说,资源仅为Unix库。 - BestR
@Swift 是另一个程序,我无法控制它。 - BestR
@eryksun 怎么做? - BestR
2个回答

6

一个作业对象支持限制进程的已提交内存。在Python中,我们可以通过PyWin32或ctypes实现这一点。

请注意,在Windows 8之前,一个进程只能处于一个作业中。其中一些常见情况包括py.exe启动器(.py文件的默认关联),它在作业中运行python.exe,以及任务计划程序服务,它在作业中运行每个任务。

PyWin32示例

import sys
import warnings

import winerror
import win32api
import win32job

g_hjob = None

def create_job(job_name='', breakaway='silent'):
    hjob = win32job.CreateJobObject(None, job_name)
    if breakaway:
        info = win32job.QueryInformationJobObject(hjob,
                    win32job.JobObjectExtendedLimitInformation)
        if breakaway == 'silent':
            info['BasicLimitInformation']['LimitFlags'] |= (
                win32job.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
        else:
            info['BasicLimitInformation']['LimitFlags'] |= (
                win32job.JOB_OBJECT_LIMIT_BREAKAWAY_OK)
        win32job.SetInformationJobObject(hjob,
            win32job.JobObjectExtendedLimitInformation, info)
    return hjob

def assign_job(hjob):
    global g_hjob
    hprocess = win32api.GetCurrentProcess()
    try:
        win32job.AssignProcessToJobObject(hjob, hprocess)
        g_hjob = hjob
    except win32job.error as e:
        if (e.winerror != winerror.ERROR_ACCESS_DENIED or
            sys.getwindowsversion() >= (6, 2) or
            not win32job.IsProcessInJob(hprocess, None)):
            raise
        warnings.warn('The process is already in a job. Nested jobs are not '
            'supported prior to Windows 8.')

def limit_memory(memory_limit):
    if g_hjob is None:
        return
    info = win32job.QueryInformationJobObject(g_hjob,
                win32job.JobObjectExtendedLimitInformation)
    info['ProcessMemoryLimit'] = memory_limit
    info['BasicLimitInformation']['LimitFlags'] |= (
        win32job.JOB_OBJECT_LIMIT_PROCESS_MEMORY)
    win32job.SetInformationJobObject(g_hjob,
        win32job.JobObjectExtendedLimitInformation, info)

def main():
    assign_job(create_job())
    memory_limit = 100 * 1024 * 1024 # 100 MiB
    limit_memory(memory_limit)
    try:
        bytearray(memory_limit)
    except MemoryError:
        print('Success: available memory is limited.')
    else:
        print('Failure: available memory is not limited.')
    return 0

if __name__ == '__main__':
    sys.exit(main())

谢谢您的回答!然而,我仍然不明白如何使用这段代码。比如说,我有一个名为run_pipeline()的函数,我想设置它的RAM限制,那么我应该在这段代码中的哪里放置run_pipeline()函数呢? - Lilianna
1
@Lilianna,通过assign_job(create_job())将进程分配给Job对象。然后,limit_memory(memory_limit)配置适用于作业中所有进程的内存限制。随后,调用您的run_pipeline函数将受到内存限制的约束。请注意,默认情况下,作业以静默断开模式创建,因此只有当前进程位于作业中,即您不必担心子进程受此限制的影响。 - Eryk Sun
有什么想法解决这个错误:Assertion failed: error not defined [8] (C:\ci\zeromq_1599741307349\work\src\ip.cpp:481) 我在运行以上代码时遇到了这个错误。 - Talha Anwar

2
我遇到了与OP类似的问题,但我想限制使用的物理RAM数量,而不是虚拟内存。@eryksun的回答和limit_memory()函数非常好用,但它们限制的是可分配内存(虚拟内存)的总量。这里是一个额外的函数,可以限制物理内存("工作集")的数量。"最初的回答"
def limit_working_set(memory_limit):
    if g_hjob is None:
        return
    info = win32job.QueryInformationJobObject(g_hjob, win32job.JobObjectBasicLimitInformation)
    info['MinimumWorkingSetSize'] = 50 * 4096  # default minimum value
    info['MaximumWorkingSetSize'] = memory_limit
    info['LimitFlags'] = (win32job.JOB_OBJECT_LIMIT_WORKINGSET)
    win32job.SetInformationJobObject(g_hjob, win32job.JobObjectBasicLimitInformation, info)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接