Live data from Hacker News

Tracking down a memory leak in Ruby's EventMachine

blog.nelhage.com

21–30 of 33 posts

Re: Tracking down a memory leak in Ruby's EventMachine

#21
This is slightly off-topic, but I worked on a Ruby project where we did something just like this:

"It was easy enough to work around the leak by adding monitoring and restarting the process whenever memory usage grew too large"

I was surprised, because I can not think of any other language and/or framework where "just restart the process" is done so often. I mean, this is not a common attitude among Java programmers, I don't think it is common among C programmers, and I don't think it is common among Python programmers. But it does seem to be fairly standard in the Ruby community. David Heinemeier Hansson admitted this used to happen with Basecamp:

http://david.heinemeierhansson.com/posts/31-myth-2-rails-is-...

Can anyone else tell me of a community where this is done so commonly?

Re: Tracking down a memory leak in Ruby's EventMachine

#22
post #4

Like danso, I admire the detective-work here. I would like to point out, though, that XCode's Instruments utility has a fantastically useful "Leaks" mode that will identify leaked allocations, including a stack trace. It can attach to a running process and has a non-disastrous impact on performance, though like most such tools it's voracious for memory. Other platforms likely have similar tools, though I have yet to…

I actually think there's something more remarkable about figuring this out by hand, in the command line. And writing about it, just the fact that you can capture the exact steps taken with a simple copy and paste blows the GUI approach well out of the water.

This was the work of someone who knew what they were doing, of course. Had it been, say, me, then the effect and utility of the piece would have been considerably lacking.

Re: Tracking down a memory leak in Ruby's EventMachine

#23

This is slightly off-topic, but I worked on a Ruby project where we did something just like this: "It was easy enough to work around the leak by adding monitoring and restarting the process whenever memory usage grew too large" I was surprised, because I can not think of any other language and/or framework where "just restart the process" is done so often. I mean, this is not a common attitude among Java programmers,…

Windows. Turning it off and on again always fixes the BSOD.

Re: Tracking down a memory leak in Ruby's EventMachine

#24

This is slightly off-topic, but I worked on a Ruby project where we did something just like this: "It was easy enough to work around the leak by adding monitoring and restarting the process whenever memory usage grew too large" I was surprised, because I can not think of any other language and/or framework where "just restart the process" is done so often. I mean, this is not a common attitude among Java programmers,…

That was five years ago. That's not really relevant anymore. It used to be a quick fix but many things have changed since then.

Re: Tracking down a memory leak in Ruby's EventMachine

#25

This is slightly off-topic, but I worked on a Ruby project where we did something just like this: "It was easy enough to work around the leak by adding monitoring and restarting the process whenever memory usage grew too large" I was surprised, because I can not think of any other language and/or framework where "just restart the process" is done so often. I mean, this is not a common attitude among Java programmers,…

Hacker News itself does this.

> We restart HN every 5 or 6 days, or it gets slow (memory leaks). [1]

pg went into more depth about this somewhere, but I don't have the link on hand at the moment. Essentially, the software running it is riddled with memory leaks, but it's more time-efficient to simply reboot it every so often than it is to actually go in and fix it.

[1] https://news.ycombinator.com/item?id=4730251

Re: Tracking down a memory leak in Ruby's EventMachine

#26
post #19

Earlier quoted context omitted.

Deduction is great, but what I read here was how much experience matters in debugging. You have to know what to look and test for to provide fodder for your reasoning capabilities, or else you're just shooting in the dark. The OP here had a plan informed by what I'm guessing are years of experience solving this kind of thing ("It's probably small objects. I should dump the core and look for repeating memory patterns.…

Yes, this is true, so as I said, debugging looks easier in hindsight, especially someone else's hindsight :) Summarizing the reasoning process: 1. The program's object space doesn't contain an absurd number of small objects, so inspect the core dump 2. 95% of the core dump is leaked objects, so a random sample should contain clues to the composition of the leaked objects. 3. A repeated pattern in every leaked object…

I am familiar with step 3, but I don't even know where to begin with step 4. I guess it'll remain a mystery... 4ever.

Re: Tracking down a memory leak in Ruby's EventMachine

#28
post #26
post #19

Earlier quoted context omitted.

Yes, this is true, so as I said, debugging looks easier in hindsight, especially someone else's hindsight :) Summarizing the reasoning process: 1. The program's object space doesn't contain an absurd number of small objects, so inspect the core dump 2. 95% of the core dump is leaked objects, so a random sample should contain clues to the composition of the leaked objects. 3. A repeated pattern in every leaked object…

I am familiar with step 3, but I don't even know where to begin with step 4. I guess it'll remain a mystery... 4ever.

The reasoning is reasonably well explained in the article, I think?

Noting there is an identical pointer in each object, assume this is a pointer to some kind of type definition struct. What will this have in it? There'll likely be a type name, some function pointers for standard operations, maybe a link to any more definitions, that kind of thing. This kind of arrangement is just something you do in C and C++. It's very common.

So take a look at what's at that address, under the assumption it's just a block of pointers. And then look at the first pointer (0x401 is obviously not a pointer). And in this case he got lucky, because it points to a suggestive string. (It could just as easily have pointed to another type definition, or something random. Though it's not uncommon for descriptors to have the name in the first field or two.)

Object type names are usually string literals so it's likely to point into the data segment of an EXE or DLL. (Maybe on Linux you can guess that from the address as well.) That's what the maps thing is all about - figuring out where the string might come from as a way of narrowing down the search.

Re: Tracking down a memory leak in Ruby's EventMachine

#29
I found a bug in eventmachine during the time I spent writing em-zeromq, the eventmachine binding for zeromq. The important thing to understand here is that ZMQ is, in-essence, a userland socket. Normal sockets are efficiently monitored using the epoll system call (or one of its older variants, say select, or poll). However, as a user-land program

ZMQ 'sockets' aren't compatible with those calls, they use a userland equivalent of those kernel level edge triggered pollers. Integrating ZMQ with a traditional event library (like eventmachine) presents a problem at this point, as software like EM or Node typically require IO to be across real file descriptors from real sockets, something a userland library can't provide. The ZMQ devs however realized this was a hotly requested feature and so devised a way around this limitation.

The compatibility layer in ZMQ takes the form of performing some internal communication across traditional unix IPC, in the case using a pipe IIRC. In other words, for some of its internal messaging rather than simply use a function call, ZMQ will push data across a pipe. This pipe can then be exposed as a proxy for a ZMQ socket.

The downside of this strategy is that exposing FDs across software requires extreme care. Generally, it is assumed that one piece of software will have responsibility for an FD.

The actual issue in my case was that any ruby exception would cause the entire process to crash with an error about closing an already closed FD. What was happening was that given an exception both ZMQ and EM were trying to shut down all the FDs they knew about. Closing an FD that's already closed causes ZMQ to assert and crash instantly. It sounds simple once you're in the right frame of mind, but it took a good number of evenings to track down to that cause. It turned out the the EM option to not shut-down FDs was non-functional in the end. A one character patch provided the fix.

Re: Tracking down a memory leak in Ruby's EventMachine

#30

This is slightly off-topic, but I worked on a Ruby project where we did something just like this: "It was easy enough to work around the leak by adding monitoring and restarting the process whenever memory usage grew too large" I was surprised, because I can not think of any other language and/or framework where "just restart the process" is done so often. I mean, this is not a common attitude among Java programmers,…

Hacker News itself does this. > We restart HN every 5 or 6 days, or it gets slow (memory leaks). [1] pg went into more depth about this somewhere, but I don't have the link on hand at the moment. Essentially, the software running it is riddled with memory leaks, but it's more time-efficient to simply reboot it every so often than it is to actually go in and fix it. [1] https://news.ycombinator.com/item?id=4730251

That might work for HN, but it doesn't really matter if HN is down for a while. For something like Basecamp (the original 'restart it every few minutes' example, it does not seem nearly as professional.
Post reply on HN