Live data from Hacker News

Diagnosing Memory “Leaks” in Python

chase-seibert.github.io

21–30 of 32 posts

Re: Diagnosing Memory “Leaks” in Python

#21
post #13
post #2

Kind of surprised the poster didn't know that operating systems often hold on to memory. > we noticed that the memory of the celery process was continuing to grow. Doesn't look like there was any bad outcome related to this observation. Was any process not getting the memory it wanted?

There are in fact bad outcomes of continued memory growth - firstly there is a catastrophic performance degradation when processes start getting swapped to disk, then when swap space runs out Linux's OOM killer starts killing processes in an attempt to free up memory. Kind of surprised you didn't know this.

buy more RAM

KIND OF SURPRISED YOU DIDN'T BUY MORE RAM

Re: Diagnosing Memory “Leaks” in Python

#22
post #13
post #2

Kind of surprised the poster didn't know that operating systems often hold on to memory. > we noticed that the memory of the celery process was continuing to grow. Doesn't look like there was any bad outcome related to this observation. Was any process not getting the memory it wanted?

There are in fact bad outcomes of continued memory growth - firstly there is a catastrophic performance degradation when processes start getting swapped to disk, then when swap space runs out Linux's OOM killer starts killing processes in an attempt to free up memory. Kind of surprised you didn't know this.

Except that didn't happen, according to the post.

Re: Diagnosing Memory “Leaks” in Python

#23
post #19

Once I had to fix a severe memory leak in piece of Python code. None of the available tools revealed anything useful. I ended up just adding debug statements to the hot loop to see which step caused the memory usage to jump. Should have known the answer: a bad C extension was leaking memory. Lesson learned.

libzmq apparently has a bug where it creates structures to handle connections every time you connect, and it cleans them up after processing data. This means that if you connect then disconnect without sending data, you leak memory. It's trivial to run a "for i in …" and cause a zmq app to leak gigabytes of memory in a matter of seconds. Highly problematic.

Are you referring to https://news.ycombinator.com/item?id=10175751 ?

Re: Diagnosing Memory “Leaks” in Python

#24

I encountered the "memory hogging" behavior of Python processes once, where I was sure that my GC worked correctly and that I released all unused objects but still the memory of the process would keep growing. I also remember having this problem with a C++ once as well. It doesn't seem a problem though since the OS should normally release the memory if it's needed by another process. Still, this kind of behavior can…

Except under Linux fork() has COW semantics, so only heap variables that change will be copied, thou I suspect that could be a large portion of a Python process anyway

Re: Diagnosing Memory “Leaks” in Python

#25
post #9

Earlier quoted context omitted.

If you find one, let me know ;) I'm looking for something myself currently. There's RQ ( http://python-rq.org/ ) but it seems to have a similar design as Celery (just a simpler architecture) so it probably suffers from the same problem. A good solution would be to have a series of workers that can launch new independent Python processes for each task, e.g. using the subprocess module.

I have long running jobs (say, 5 minutes on average - up to an hour). I originally used celery (after picloud shut down) but it just doesn't work well with those charcteristics. Each worker reserved an extra job so it was impossible to get good cpu utilisation. I switched to rq and it's all been much easier. The behaviour is easy to understand and it's easy to inspect redis to see what's going on. In terms of the cod…

Thanks, that sounds interesting!

Re: Diagnosing Memory “Leaks” in Python

#26
post #24

I encountered the "memory hogging" behavior of Python processes once, where I was sure that my GC worked correctly and that I released all unused objects but still the memory of the process would keep growing. I also remember having this problem with a C++ once as well. It doesn't seem a problem though since the OS should normally release the memory if it's needed by another process. Still, this kind of behavior can…

Except under Linux fork() has COW semantics, so only heap variables that change will be copied, thou I suspect that could be a large portion of a Python process anyway

Yes the operation is quite efficient, the problem is that fork() normally makes reloading of code (without resorting to special tricks) impossible, as the interpreter will usually already have loaded all imports before forking. The only way to circumvent this would be to delay the loading of required modules until after the fork.

Re: Diagnosing Memory “Leaks” in Python

#27
post #18

I encountered the "memory hogging" behavior of Python processes once, where I was sure that my GC worked correctly and that I released all unused objects but still the memory of the process would keep growing. I also remember having this problem with a C++ once as well. It doesn't seem a problem though since the OS should normally release the memory if it's needed by another process. Still, this kind of behavior can…

We solved the Celery + long running + code reloading problem by having each push of new code be associated with a new Celery queue. On push of new code, start the new queue, and SIGTERM the old one, which will wait for any long-running tasks to finish before exiting.

[deleted]

Re: Diagnosing Memory “Leaks” in Python

#28
post #18

I encountered the "memory hogging" behavior of Python processes once, where I was sure that my GC worked correctly and that I released all unused objects but still the memory of the process would keep growing. I also remember having this problem with a C++ once as well. It doesn't seem a problem though since the OS should normally release the memory if it's needed by another process. Still, this kind of behavior can…

We solved the Celery + long running + code reloading problem by having each push of new code be associated with a new Celery queue. On push of new code, start the new queue, and SIGTERM the old one, which will wait for any long-running tasks to finish before exiting.

Hm that's an interesting idea, thanks for sharing this! How exactly do you perform the restart of the Celery service and where are your queues configured? I guess you don't specify them in /etc/defaults/celeryd?

Re: Diagnosing Memory “Leaks” in Python

#29
post #22
post #13

Earlier quoted context omitted.

There are in fact bad outcomes of continued memory growth - firstly there is a catastrophic performance degradation when processes start getting swapped to disk, then when swap space runs out Linux's OOM killer starts killing processes in an attempt to free up memory. Kind of surprised you didn't know this.

Except that didn't happen, according to the post.

The post says: "Indeed, the processes grew from their initial size of 100MB, slowly, all the way up to 1GB before we killed them."

The important part is that they manually killed the processes before they let it start swapping.

Re: Diagnosing Memory “Leaks” in Python

#30

If you think you actually have a memory leak in python, the first thing to do is to recompile without the internal memory manager in python. This avoids the problem the author is addressing.

Can you expand on this a little more or provide some links that explain? What happens to memory if you remove the memory manager?

It just uses the provided malloc & free implementations from the underlying C standard library.
Post reply on HN