Python写时复制或访问时复制共享内存

Posted

技术标签:

【中文标题】Python写时复制或访问时复制共享内存【英文标题】:Python copy-on-write or copy-on-access shared memory 【发布时间】:2021-04-05 23:29:11 【问题描述】:

我试图了解进程之间共享内存的工作原理,但我陷入了困境。 我正在使用一个非常简单的测试程序 c.py 并使用 smem

跟踪内存

c.py:

import sys
import time
from multiprocessing import Process

arr = [x for x in range(int(1e6) * 50)]
print(sys.getsizeof(arr))  # 411943896

def f():
    x = 0
    for i in range(len(arr)):
        #x += arr[i]
        pass
    time.sleep(10)

p = Process(target=f)
p.start()
p.join()

当我在 x += arr[i] 注释掉的情况下运行它时,我看到以下结果:

PID User     Command                         Swap      USS      PSS      RSS
  1693779 1000     python /usr/bin/smem -n -t         0     8368     9103    14628
  1693763 1000     python c.py                        0     1248   992816  1986688
  1693749 1000     python c.py                        0     1244   993247  1989752
  -------------------------------------------------------------------------------
      3 1                                           0    10860  1995166  3991068

如果我理解正确,PSS 告诉我我的单个全局数组 arr 在两个进程之间共享,而 USS 显示每个进程分配的唯一内存非常少。

但是,当我取消注释 x += arr[i] 仅在子进程中访问数组元素 会产生非常不同的结果:

PID User     Command                         Swap      USS      PSS      RSS
  1695338 1000     python /usr/bin/smem -n -t         0     8476     9508    14392
  1695296 1000     python c.py                       64  1588472  1786582  1986708
  1695280 1000     python c.py                        0  1588644  1787246  1989520
  -------------------------------------------------------------------------------
      3 1                                          64  3185592  3583336  3990620

我不明白。似乎访问数组导致它被复制到子进程,这意味着python实际上是在访问时复制共享内存,而不是在写入时。

    我的理解正确吗?访问全局变量arr 时,是否已将arr 数据所在的内存复制到子进程?

    如果是这样,子进程是否无法在不增加内存使用量的情况下访问全局变量?

    如果有人可以解释整体内存使用情况 smem 报告,我会很高兴,但是,在这种情况下,我希望这是一个更适合 SU? 的问题。如果发生简单的复制,我希望内存翻倍,但是每个进程显示的唯一内存为 1588472,并且在整个 PSS 共享内存之上是 2x 1786582,所以总计约为 6750108?我很确定我在这里的理解是非常错误的,但我不知道如何解释它。

【问题讨论】:

【参考方案1】:

正在写入元素。 Python 的标准实现使用引用计数,因此即使查看对象也需要写入其引用计数。

【讨论】:

我想我不明白。你的意思是x = x + arr[1] 操作增加了对对象 arr 的引用计数? @zrf:您是否将其视为 C 风格的连续内存数组? Python 列表由指向对象的指针数组支持,每个对象都有自己的引用计数。 是的,我想我是这么想的。现在开始变得更有意义了。我假设引用计数器与对象保存在同一内存区域中,这就是触发数组复制的原因 instagram-engineering.com/….

以上是关于Python写时复制或访问时复制共享内存的主要内容,如果未能解决你的问题,请参考以下文章

Linux写时复制(CopyOnWrite)|写时拷贝|rcu

再谈QVector与QByteArray——Qt的写时复制(copy on write)技术

再谈QVector与QByteArray——Qt的写时复制(copy on write)技术

PHP 内存管理 写时复制 垃圾回收

在Swift结构体中如何实现写时复制?

虚拟内存与写时复制