如何在python中设置线程或进程的内存限制?
我正在用Python编写程序,可以在某种沙箱中运行不受信任的Python代码。因此,我需要一种方法来限制不可信代码可以分配的内存量。现在,我可以通过覆盖沙盒环境中的默认python数据结构来限制range()、list、dictionary和其他的最大长度 有什么想法吗?在Unix下,您可以使用 “进程可能占用的最大地址空间面积(字节)。”如何在python中设置线程或进程的内存限制?,python,multithreading,python-2.7,cross-platform,Python,Multithreading,Python 2.7,Cross Platform,我正在用Python编写程序,可以在某种沙箱中运行不受信任的Python代码。因此,我需要一种方法来限制不可信代码可以分配的内存量。现在,我可以通过覆盖沙盒环境中的默认python数据结构来限制range()、list、dictionary和其他的最大长度 有什么想法吗?在Unix下,您可以使用 “进程可能占用的最大地址空间面积(字节)。” 我不知道在Windows下是怎么做的。希望其他人可以 提供解决方案的这一部分 下面是一些使用ctypes设置Windows限制的示例代码 import ct
我不知道在Windows下是怎么做的。希望其他人可以 提供解决方案的这一部分 下面是一些使用
ctypes
设置Windows限制的示例代码
import ctypes
PROCESS_SET_QUOTA = 0x100
PROCESS_TERMINATE = 0x1
JobObjectExtendedLimitInformation = 9
JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x100
class IO_COUNTERS(ctypes.Structure):
_fields_ = [('ReadOperationCount', ctypes.c_uint64),
('WriteOperationCount', ctypes.c_uint64),
('OtherOperationCount', ctypes.c_uint64),
('ReadTransferCount', ctypes.c_uint64),
('WriteTransferCount', ctypes.c_uint64),
('OtherTransferCount', ctypes.c_uint64)]
class JOBOBJECT_BASIC_LIMIT_INFORMATION(ctypes.Structure):
_fields_ = [('PerProcessUserTimeLimit', ctypes.c_int64),
('PerJobUserTimeLimit', ctypes.c_int64),
('LimitFlags', ctypes.c_uint32),
('MinimumWorkingSetSize', ctypes.c_void_p),
('MaximumWorkingSetSize', ctypes.c_void_p),
('ActiveProcessLimit', ctypes.c_uint32),
('Affinity', ctypes.c_void_p),
('PriorityClass', ctypes.c_uint32),
('SchedulingClass', ctypes.c_uint32)]
class JOBOBJECT_EXTENDED_LIMIT_INFORMATION(ctypes.Structure):
_fields_ = [('BasicLimitInformation', JOBOBJECT_BASIC_LIMIT_INFORMATION),
('IoInfo', IO_COUNTERS),
('ProcessMemoryLimit', ctypes.c_void_p),
('JobMemoryLimit', ctypes.c_void_p),
('PeakProcessMemoryUsed', ctypes.c_void_p),
('PeakJobMemoryUsed', ctypes.c_void_p)]
# Set memory limit for process with specfied 'pid', to specified 'size' in bytes
def set_limit(pid, size):
job_info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
out_size = ctypes.c_uint32()
job = ctypes.windll.kernel32.CreateJobObjectA(None, None)
assert job != 0
success = ctypes.windll.kernel32.QueryInformationJobObject(job,
JobObjectExtendedLimitInformation,
ctypes.POINTER(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)(job_info),
ctypes.sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
ctypes.POINTER(ctypes.c_uint32)(out_size))
assert success
job_info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY
job_info.ProcessMemoryLimit = size
success = ctypes.windll.kernel32.SetInformationJobObject(job,
JobObjectExtendedLimitInformation,
ctypes.POINTER(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)(job_info),
ctypes.sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))
assert success
process = ctypes.windll.kernel32.OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE,
False, pid)
assert process != 0
success = ctypes.windll.kernel32.AssignProcessToJobObject(job, process)
assert success
success = ctypes.windll.kernel32.CloseHandle(job)
assert success
success = ctypes.windll.kernel32.CloseHandle(process)
assert success
if __name__ == '__main__':
import os
five_mb = 5 * 1024 * 1024
def can_we_allocate_five_mb():
try:
s = 'x' * five_mb
return True
except MemoryError:
return False
print can_we_allocate_five_mb()
set_limit(os.getpid(), five_mb)
print can_we_allocate_five_mb()
…虽然可能不需要为每个进程创建单独的作业对象,但您应该能够将所有受限制的进程与单个作业关联。您可能只需要在操作系统级别执行此操作,而不是在Python内部(例如,在Windows中,您可能希望使用作业对象)。将有助于指定您需要使用的操作系统。我的操作系统是Windows,但我计划以跨平台的方式进行所有操作。如果没有特定于操作系统的代码,您真的无法做到这一点,因为现有操作系统(Windows、Mac、Linux等)变化太大。您可以从
子流程
中获得提示:导入sys
,然后使用类似mswindows=(sys.platform==“win32”)
的代码,如果mswindows:。。。其他:…。很好!但是这些Windows机器怎么办?我不知道在Windows下是怎么做的。希望其他人能够提供这部分解决方案。在Python 3中,您需要使用CreateJobObjectW而不是CreateJobObjectA,否则Windows只能看到作业名称的第一个字符。
import ctypes
PROCESS_SET_QUOTA = 0x100
PROCESS_TERMINATE = 0x1
JobObjectExtendedLimitInformation = 9
JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x100
class IO_COUNTERS(ctypes.Structure):
_fields_ = [('ReadOperationCount', ctypes.c_uint64),
('WriteOperationCount', ctypes.c_uint64),
('OtherOperationCount', ctypes.c_uint64),
('ReadTransferCount', ctypes.c_uint64),
('WriteTransferCount', ctypes.c_uint64),
('OtherTransferCount', ctypes.c_uint64)]
class JOBOBJECT_BASIC_LIMIT_INFORMATION(ctypes.Structure):
_fields_ = [('PerProcessUserTimeLimit', ctypes.c_int64),
('PerJobUserTimeLimit', ctypes.c_int64),
('LimitFlags', ctypes.c_uint32),
('MinimumWorkingSetSize', ctypes.c_void_p),
('MaximumWorkingSetSize', ctypes.c_void_p),
('ActiveProcessLimit', ctypes.c_uint32),
('Affinity', ctypes.c_void_p),
('PriorityClass', ctypes.c_uint32),
('SchedulingClass', ctypes.c_uint32)]
class JOBOBJECT_EXTENDED_LIMIT_INFORMATION(ctypes.Structure):
_fields_ = [('BasicLimitInformation', JOBOBJECT_BASIC_LIMIT_INFORMATION),
('IoInfo', IO_COUNTERS),
('ProcessMemoryLimit', ctypes.c_void_p),
('JobMemoryLimit', ctypes.c_void_p),
('PeakProcessMemoryUsed', ctypes.c_void_p),
('PeakJobMemoryUsed', ctypes.c_void_p)]
# Set memory limit for process with specfied 'pid', to specified 'size' in bytes
def set_limit(pid, size):
job_info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
out_size = ctypes.c_uint32()
job = ctypes.windll.kernel32.CreateJobObjectA(None, None)
assert job != 0
success = ctypes.windll.kernel32.QueryInformationJobObject(job,
JobObjectExtendedLimitInformation,
ctypes.POINTER(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)(job_info),
ctypes.sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
ctypes.POINTER(ctypes.c_uint32)(out_size))
assert success
job_info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY
job_info.ProcessMemoryLimit = size
success = ctypes.windll.kernel32.SetInformationJobObject(job,
JobObjectExtendedLimitInformation,
ctypes.POINTER(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)(job_info),
ctypes.sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))
assert success
process = ctypes.windll.kernel32.OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE,
False, pid)
assert process != 0
success = ctypes.windll.kernel32.AssignProcessToJobObject(job, process)
assert success
success = ctypes.windll.kernel32.CloseHandle(job)
assert success
success = ctypes.windll.kernel32.CloseHandle(process)
assert success
if __name__ == '__main__':
import os
five_mb = 5 * 1024 * 1024
def can_we_allocate_five_mb():
try:
s = 'x' * five_mb
return True
except MemoryError:
return False
print can_we_allocate_five_mb()
set_limit(os.getpid(), five_mb)
print can_we_allocate_five_mb()