[Python-bugs-list] [ python-Bugs-704180 ] Memory leak: threading.Thread.__init__(self, target=self.xx)
SourceForge.net
noreply@sourceforge.net
Sat, 22 Mar 2003 13:30:54 -0800
Bugs item #704180, was opened at 2003-03-15 17:44
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=704180&group_id=5470
Category: Threads
Group: Python 2.2.2
Status: Closed
Resolution: Invalid
Priority: 5
Submitted By: Darrell Gallion (dgallion)
Assigned to: Nobody/Anonymous (nobody)
Summary: Memory leak: threading.Thread.__init__(self, target=self.xx)
Initial Comment:
This call
threading.Thread.__init__(self, target=self.xxx)
makes this assignment
self.__target = target
Which looks like a circular refrence to me.
weakref anyone ?
The following test code shows the leak in action.
--Darrell
import threading, time
class T1(threading.Thread):
def __init__(self, leak=0):
self.leak=leak
if leak:
threading.Thread.__init__(self, target=self.m1)
else:
threading.Thread.__init__(self)
self.start()
def run(self):
pass
def m1(self):
pass
def __del__(self):
print 'DEL:', self, "leak:",self.leak
for x in range(10):
T1(leak=1)
for x in range(10):
T1()
time.sleep(1)
----------------------------------------------------------------------
>Comment By: Martin v. Löwis (loewis)
Date: 2003-03-22 22:30
Message:
Logged In: YES
user_id=21627
That won't work. In your example, the method object is
created with the expression self.m1, and the only reference
to it is the target parameter. So if Thread would keep just
a weak reference to target, then the method object would go
away just after __init__ completes. As the result, the
Thread's .run won't find the target.
----------------------------------------------------------------------
Comment By: Darrell Gallion (dgallion)
Date: 2003-03-22 21:36
Message:
Logged In: YES
user_id=68151
Using a threading.Thread as a base class invites you to pass target methods
other than run. Which sets up the cycle. It would be nice if the target could
be a weakref or was converted to a weakref by Thread.
This simple change would prevent others from wasting time on this problem.
----------------------------------------------------------------------
Comment By: Martin v. Löwis (loewis)
Date: 2003-03-21 19:22
Message:
Logged In: YES
user_id=21627
I fail to see a bug in Python here. You are passing a
reference to an object to the __init__ of the base class, so
you should know you are creating cycles.
I recommend to re-implement T1.run instead of using the
target= constructor argument.
----------------------------------------------------------------------
Comment By: Darrell Gallion (dgallion)
Date: 2003-03-16 17:45
Message:
Logged In: YES
user_id=68151
I know about the __del__ issue with gc, and your right this example worked
fine with it removed. The much larger app that sent me on this chase wasn't
fixed by the __del__ method. Yet it was fixed by moving the target method
to a function call instead of a method on the object.
It's a large app and the timing of when an object is destroyed matters.
The following helps me see my problem.
import threading, time, weakref
class T1(threading.Thread):
def __init__(self):
self.go=1
threading.Thread.__init__(self, target=self.m1)
self.start()
def m1(self):
while self.go:
time.sleep(0.0001)
objs={}
while 1:
t1 = weakref.ref(T1())
objs[t1]=1
t1().go=0
time.sleep(0.01)
for o in objs.keys():
if o() == None:
del objs[o]
print len(objs),
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2003-03-16 05:39
Message:
Logged In: YES
user_id=31435
The "leak" is due to that you gave this class a __del__
method: cyclic garbage collection won't magically reclaim
objects in cycles with __del__ methods. Remove the
__del__ and you can run this all day without the process
size growing. If you leave the __del__ in, you can find all
your uncollectible thread objects in gc.garbage (and use
that to break the cycles and get them collected, if you like --
I'd recommend not using __del__ at all, though).
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=704180&group_id=5470