在Python中删除传递给函数的变量引用
给定以下代码:在Python中删除传递给函数的变量引用,python,memory-management,Python,Memory Management,给定以下代码: 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
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)
在func
中执行del x
后,是否可以更改func1
以降低内存消耗?(因为传递给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
在请求func2之前,将x
传递给func2
,并删除其对x
的内部引用。如果你这样做
x=42
现在有两件事-有一个包含值42的“integer”对象,还有一个指向该integer对象的指针“x”
执行删除x操作时,删除的是指针。请记住,该函数中的x
在任何其他上下文中都不是x
。integer对象本身通过引擎盖下的引用计数进行管理。如果没有其他变量指向它,那么解释器将在某个时候继续删除它
若要尝试节省内存,请想象func正在从数组中提取一小块并处理它。当它完成时,没有其他东西需要那片,所以把它扔掉,对吗?有两种可能性
您已完成切片,最后一个引用已消失。。。解释器最终将从内存中删除切片对象
您使用的是numpy(看起来是这样),代码的实现方式使它实际上不会生成副本,但允许您在原有的数据结构上进行操作。在这种情况下,切片只是一个指向数据的指针,而不是数据,因此删除它并不会带来太多好处
不管是哪种方式,您可能在这里寻找错误的位置来尝试保存内存。在当前的CPython实现下,在执行Python函数调用时,调用方保留所有参数引用的所有权,直到调用完成。被调用方不转移所有权,而是获取新的或借用的引用(取决于被调用方的实现方式,尤其是它是用C还是Python编写的)
无法将所有权转移给被调用方,被调用方也无法清除调用方的引用。即使尝试类似于pop
的技巧来确保调用方没有引用参数的变量,调用方的字节码操作数堆栈中仍然存在引用,并且该引用只有在调用完成后才会被清除。(您可以在CPython中看到这一点。)
你最好直接将包装器列表传递给func2
,除非你说你无权访问func2
的源代码,所以你不能修改它来获取这样的列表
您的运气太差了。func1
仍然有自己对x
的引用,并将继续这样做,直到func2()
返回。您在func2
中所能做的任何事情都无法删除该引用。使用可适当减小数组的大小。func1中是否实际使用了func2的返回值?@wwi否,它是not@Barmar遗憾的是,我无法访问func2
的源代码,否则,我可以传递封装在列表中的x,并将其从func2
中的列表中删除。