A nasty little memory leak

5

0

Below Python code generates memory leak.

Challenge: Fix the memory leak with minimal changes to the code as measured by Levenshtein distance to the original code. You may only change the code before t is initialised. When the del t line is removed the modified program should print I'm still alive! every second.

PS: I already know the answer (found it after several hours of debugging). This is not the programming help question! Hopefully this would be interesting to folks.

import threading, time

# this class takes callback and calls it every 1 sec
class MyTimer:
    def __init__(self, callback):
        self.callback = callback
        self.th = threading.Thread(target=self.run,daemon=True)
        self.th.start()
    def run(self):
        while(True):
            self.callback()
            time.sleep(1)

class TestMyTimer:
    def __init__(self):
        self.timer = MyTimer(self.is_alive)
    def is_alive(self):
        print("I'm still alive")

# test code for MyTimer
t = TestMyTimer()
del t

# just to be sure to collect all dead objects
import gc
gc.collect()

# if you are still seeing messages then we have memory leak!
time.sleep(60)

Here's repl.it to play with this code online.

Shital Shah

Posted 2019-02-26T02:03:20.697

Reputation: 191

1Ah, rereading this, I see that you're aware of the answer to your problem. However, on PPCG, the puzzles tend to be challenges for which we write code to solve the criteria, rather than solve a puzzle in a piece of code. The closest tag I can see for this is the rarely used [tag:programming-puzzle] (which is often mistagged), but you would still need an objective winning criterion (i.e. what makes one answer to your question better than a different answer) to make this challenge on-topic – Jo King – 2019-02-26T03:58:21.600

2

In the future, it might be best to look through and answer some existing challenges, and make sure to post future challenges in the Sandbox to gauge community reactions before posting to main.

– Jo King – 2019-02-26T03:58:25.277

Unfortunately this was closed for the wrong reason. PPCG is a bit odd in that we require each challenge to have an objective way to compare answers against each other (and generally "first poster" is frowned upon). If I had to guess, the best way to get this information out would be to post a question on SO and self answer it. The "gotcha" is fairly elusive, and I wouldn't have guessed that it was wrong just from looking at the code. – FryAmTheEggman – 2019-02-26T05:32:34.500

3I think this could be tagged as programming-puzzle with the winning criterion being minimal editing distance to get a solution without memory leak. – Laikoni – 2019-02-26T07:56:28.277

I'm not asking for help. I already know the answer. This is indeed programming challenge! I've modified the question to be clear on this. Also added the suggested tag. – Shital Shah – 2019-02-27T00:43:13.217

I went ahead and voted to reopen just now in light of the change. Just for future reference though you might want to ping me in a comment by @ing my username if you addressed my question, that way I can vote on it. I had just assumed you were away and I hadn't noticed that you had fixed the issue. – Post Rock Garf Hunter – 2019-02-27T03:05:21.030

5An additional thought: you might want to enforce that the fixed code produce a particular output, otherwise the best solution is likely to be to comment out everything (distance 6). This does prevent leaks but doesn't require any skill and probably is not what you were thinking. – Post Rock Garf Hunter – 2019-02-27T03:10:59.210

2I've added the [tag:code-challenge] as all challenges require a tag. I apologise for initially dismissing the challenge as a generic programming help question, but we get those quite often here. Voting to reopen. – Jo King – 2019-02-27T04:33:41.017

So I'm having a bit of a problem understanding what your intent here is. Are you trying to stop the timer by deleting the reference to the test object? – None – 2019-03-15T13:45:36.817

Answers

6

Taking inspiration from the comments and from the question, just by adding 3 characters I "fixed" the memory leak.

Granted, I broke everything else at the same time

import threading, time

# this class takes callback and calls it every 1 sec
class MyTimer:
    def __init__(self, callback):
        self.callback = callback
        self.th = threading.Thread(target=self.run,daemon=True)
        self.th.start()
    def run(self):
        while(True):
            self.callback()
            time.sleep(1)

class TestMyTimer:
    def __init__(self):
        self.timer = MyTimer(self.is_alive)
    def is_alive(self):
        print("I'm still alive")

# test code for MyTimer
#t = TestMyTimer()
#del t

# just to be sure to collect all dead objects
import gc
#gc.collect()

# if you are still seeing messages then we have memory leak!
time.sleep(60)

Edit: The challenge has now been properly updated :)

Selkie

Posted 2019-02-26T02:03:20.697

Reputation: 159

1LOL. Not quite there :) – Shital Shah – 2019-02-28T07:35:59.600

0

import threading, time

# this class takes callback and calls it every 1 sec
class MyTimer:
    def __init__(self, callback):
        self.a = True
        self.callback = callback
        self.th = threading.Thread(target=self.run,daemon=True)
        self.th.start()
    def run(self):
        while(True):
            self.callback(self.a)
            time.sleep(1)


class TestMyTimer:
    def __init__(self):
        self.timer = MyTimer(self.is_alive)
    def is_alive(self, k):
        print("I'm still alive")
        if not k:
            raise SystemExit()


# test code for MyTimer
t = TestMyTimer()
t.timer.a = 0
del t.timer, t

# just to be sure to collect all dead objects
import gc
gc.collect()

# if you are still seeing messages then we have memory leak!
time.sleep(60)

Dan Greenhalgh

Posted 2019-02-26T02:03:20.697

Reputation: 1

Memory leak is still there. You can check this by using objgraph library and then doing objgraph.show_backrefs(objgraph.by_type('TestMyTimer'), refcounts=True). You just stopped the timer to print the messages. – Shital Shah – 2019-03-02T00:10:29.287

Fair enough, I've edited my answer to raise the SystemExit. – Dan Greenhalgh – 2019-03-15T10:01:26.460

Please add your score to your submission – Jo King – 2019-03-15T10:08:35.030