首页 > 解决方案 > 删除传递给Python函数的变量引用

问题描述

给定以下代码:

import numpy as np
import psutil

original = np.ones(2**28) / 2

def func1(x):
    print(1,psutil.virtual_memory().percent)
    x=x**2
    print(2,psutil.virtual_memory().percent)
    func2(x)
 
def func2(x):
    print(3,psutil.virtual_memory().percent)
    y=x**2
    print(4,psutil.virtual_memory().percent)
    del x # this does not lower the memory usage
    print(5,psutil.virtual_memory().percent)
    return

func1(original)

是否有可能改变func1以降低 in 之后的内存del x消耗func?(因为传递给func2的变量不再对 有用func1)。

例如,以下内容不起作用:

import numpy as np
import psutil

original = np.ones(2**28) / 2

def func1(x):
    print(1,psutil.virtual_memory().percent)
    x=x**2
    print(2,psutil.virtual_memory().percent)
    x=[x]
    func2(x.pop())
 
def func2(x):
    print(3,psutil.virtual_memory().percent)
    y=x**2
    print(4,psutil.virtual_memory().percent)
    del x # this does not lower the memory usage
    print(5,psutil.virtual_memory().percent)
    return

func1(x)

注意:假设func2是无法更改的外部代码。

func1换句话说,我希望x在.func2xfunc2

标签: pythonmemory-management

解决方案


在当前的 CPython 实现下,当执行 Python 函数调用时,调用者保留所有参数引用的所有权,直到调用完成。被调用者不是转移所有权,而是获得新的或借用的引用(取决于被调用者的实现方式,尤其是它是用 C 还是 Python 编写的)。

无法将所有权转移给被调用者,被调用者也无法清除调用者的引用。即使您尝试使用类似pop技巧来确保调用者没有引用参数的变量,调用者的字节码操作数堆栈中仍然有一个引用,并且该引用仅在调用完成后才会被清除。(您可以在 CPython源代码中看到这一点。)

你最好的办法是直接将包装器列表传递给func2,除非你说你无权访问源代码func2,所以你不能修改它来获取这样的列表。

你很不走运。


推荐阅读