Reputation: 848
Given the following code:
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)
Would it be possible alter func1
in order to lower the memory consumption after del x
in func
? (since variable passed to func2
is no longer usefull to func1
).
For instance, the following does not work:
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)
Note: assume func2
is external code that cannot be changed.
To put in another way, I would like that func1
passed x
to func2
and deleted its internal reference to x
before the begging of func2
.
Upvotes: 0
Views: 777
Reputation: 280310
Under the current CPython implementation, when performing a Python function call, the caller retains ownership of all argument references until the call is complete. Rather than transferring ownership, the callee gets new or borrowed references (depending on how the callee is implemented, especially whether it's written in C or Python).
There is no way to transfer ownership to the callee, and no way for the callee to clear the caller's references. Even if you try something like your pop
trick to ensure the caller doesn't have a variable referring to the argument, there's still a reference living in the caller's bytecode operand stack, and that reference only gets cleared after the call is done. (You can see this in the CPython source code.)
Your best shot would be to pass the wrapper list to func2
directly, except you said you don't have access to the source code for func2
, so you can't modify it to take a list like that.
You're pretty much out of luck.
Upvotes: 1
Reputation: 9977
Python stores data objects in underlying data structures. If you do
x = 42
There are two things now - there is an "integer" object that contains a value 42, and there is a pointer "x" that points at that integer object.
When you do del x
it is the pointer that is getting deleted. Remember, x
inside that function is NOT x
in any other context. The integer object itself is managed with reference counting under the hood. If there are no other variables pointing to it, then at some point the interpreter will go ahead and delete it.
To try and save memory, imagine your func is taking a small slice from your array and working on it. When its done, nothing else ever needs that slice, so get rid of it, right? There are two possibilities...
You are done with the slice, the last reference is gone... the interpreter will eventually remove the slice object from memory.
You're using numpy (like it looks like you are) and the code is implemented in such a way that it does not actually make a copy, but allows you to operate over the original data structure in place. In this case, the slice is just a pointer to the data rather than the data, so deleting it doesn't get you much.
Either way, you're probably looking at the wrong spot to try and save memory here.
Upvotes: 0