gpt4 book ai didi

python - 为什么 Python 子进程本地的对象分配会增加 main 的堆大小?

转载 作者:行者123 更新时间:2023-12-01 05:01:14 25 4
gpt4 key购买 nike

TL;DR

根据 Valgrind 的 memcheck 工具,如果我在函数中分配一个大的局部变量并使用 multiprocessing.Pool().apply_async() 启动该函数,子进程和子进程的堆大小主进程增加。为什么 main 的堆大小会增加?

背景

我正在使用一个多处理池的工作人员,每个工作人员都将处理来自输入文件的大量数据。我想看看我的内存占用量如何根据输入文件的大小进行扩展。为此,我使用 memcheck 在 Valgrind 下运行我的脚本,并使用 this SO answer 中描述的技术。 。 (后来我了解到 Valgrind 的 Massif 工具更适合于此,因此我将继续使用它。)

memcheck 输出中有一些看起来很奇怪的东西,我希望帮助理解。

我在 Red Hat Linux 上使用 CPython 2.7.6,并像这样运行 memcheck:

valgrind --tool=memcheck --suppressions=./valgrind-python.supp python test.py

代码和输出

import multiprocessing

def mem_user():
tmp = 'a'*1
return

pool = multiprocessing.Pool(processes=1)
pool.apply_async(mem_user)

pool.close()
pool.join()

堆摘要(每个进程一个):

total heap usage: 45,193 allocs, 32,392 frees, 7,221,910 bytes allocated
total heap usage: 44,832 allocs, 22,006 frees, 7,181,635 bytes allocated

如果我将 tmp = 'a'*1 行更改为 tmp = 'a'*10000000,我会得到以下摘要:

total heap usage: 44,835 allocs, 22,009 frees, 27,181,763 bytes allocated
total heap usage: 45,195 allocs, 32,394 frees, 17,221,998 bytes allocated

问题

为什么两个进程的堆大小都会增加?我知道物体的空间是 allocated on the heap ,因此较大的堆对于其中一个进程当然是有意义的。但我希望子进程拥有自己的堆、堆栈和解释器实例,所以我不明白为什么在子进程中分配的局部变量也会增加 main 的堆大小。如果它们共享相同的堆,那么 CPython 是否实现了自己的 fork() 版本,不为子进程分配唯一的堆空间?

最佳答案

这个问题与fork的方式无关。已实现。您可以亲眼看到 multiprocessing 来电 os.fork ,这是一个非常薄的包装 fork .

那么,到底发生了什么?

编译器看到 'a' * 10000000在您的源代码中并将其优化为 10000000 个字符的文字。这意味着模块对象现在长了 10000000 字节,并且由于它是在两个进程中导入的,因此它们都会变大。

要查看此内容:

$ python2.7
>>> def f():
... temp = 'a' * 10
...
>>> f.__code__.co_consts
(None, 'a', 10, 'aaaaaaaaaa')
>>> import dis
>>> dis.dis(f)
2 0 LOAD_CONST 3 ('aaaaaaaaaa')
3 STORE_FAST 0 (temp)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE

请注意,编译器足够智能,可以添加 'aaaaaaaaaa'到常量,但还不够聪明,无法删除 'a'10 。那是因为它使用了非常窄的窥视孔优化器。除此之外,它不知道您是否也在使用 'a'在同一函数的其他地方,它不想从 co_consts 的中间删除值列出并返回并更新所有其他字节码以使用上移索引。

<小时/>

我实际上不知道为什么子进程最终会增长 20000000 字节而不是 10000000 字节。大概它最终会得到自己的模块副本,或者至少是代码对象,而不是使用从父进程共享的副本。但如果我尝试 print id(f.__code__)或者其他什么,我在父级和子级中得到相同的值,所以......

关于python - 为什么 Python 子进程本地的对象分配会增加 main 的堆大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26131803/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com