Closed Wang-Yue closed 2 years ago
Hi Wang Not so much a memory leak but the way that memory was being allocated to icons in the various screen modes dark, different icons etc in the current release does cause the memory to increase vastly as modes are changed. This has been fixed now and will be ok in the next release (or in current 3.2dev if you build yourself) it may be that this is what you are experiencing.
@rbnpi Thanks for the reply!
Are you sure the fix for the way it allocating memory for icons is related to this issue? The memory increase over time happens on the ruby
side, not the GUI(sonic-pi
).
I’ll run your example on the latest 3.2dev and see what happens.
Sent from my iPhone
On 27 Nov 2019, at 00:51, Yue Wang notifications@github.com wrote:
@rbnpi Thanks for the reply! Are you sure the fix for the way it allocating memory for icons is related to this issue? The memory increase over time happens on the ruby side, not the GUI(sonic-pi).
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
I've had a play with your example, and I do notice an increase in the memory allocated to ruby (using top on my Mac) as it runs. It looks like the memory is released again when the program stops (your code, not sonic pi). It may just be that your code is demanding increasing resources as it runs which Sonic Pi holds on to and does not release. You can certainly reduce the efffect by reducing the release time of the notes in the 16.times loop, as then release over 2 beats, whereas the loop generates a new note every 0.125 beats, which will therefore build up the resources required. Similarly the release time for play my_chord is 2 beats and the loop time is 2 beats also (16 * 0.125). You can get less memory usage by using say a release time of 1 trying
start_note = ring(60, 62, 63, 62).tick
my_chord = chord(start_note, :M7)
play my_chord, release: 1
16.times do
play my_chord.choose, release: 0.120, amp: [0.75, 0.5, 0.25].choose
sleep 0.125
end
end
give a much better "memory" performance. Evne with your original code, and a machine with reasonable memory resources it would run for a long time before becoming a problem. However on a 500Mb Pi it might give problems,especially if you have switched to dark mode which gives big increase in memory usage on the existing release 3.1 (but fixed in 3.2dev) as discussed above.
@rbnpi as I understand it, the original program should have used constant memory after running for a few seconds --- when the n+2
th live_loop
is performed, the things before n
th live_loop
no longer matter at all and any data structures specifically allocated for the previous loops on the ruby side should all be deallocated. With the modified example you gave should even be sooner, when performing the current live_loop
s, anything performed before does not matter. In either case, after 2 or 3 live_loop
s, the memory usage should be constant.
But that's not the thing we're seeing in its current memory behavior, even with your modified code. the memory usage just increased dramatically (3x) after just five minutes. Surely there is an issue in the ruby code that keeps referencing something no longer used and should had been deallocated earlier.
@rbnpi A program without memory leak does not only mean "if I stop the program, the memory gets reclaimed". Rather, it means it's not holding memory to track things no longer relevant. You can refer to the wikipedia article here: https://en.wikipedia.org/wiki/Memory_leak quote: "In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in such a way that memory which is no longer needed is not released. "
Current behavior clearly indicates a memory leak in the ruby code. My RPi has 1GB memory and it quickly runs out of all memory after 5 minutes performing my more complicated (but should have used constant memory) code.
Even if you try the following extreme simple program
live_loop :beeps do
sleep 0.125
end
the ruby memory utilization keeps increasing. This clearly means things are not right. The speed of memory increment is slower because this is a simpler program. But it still indicates something is wrong. With more complex algorithms it will surely leak much faster.
OK I take your point. I guess Sam Aaron will have to look at this. Not sure how easy it will be track down. Personally, I have not found it to be a problem, even on a Pi3 with small memory. The (now cured) memory problem with the memory consumed by changes in the gui theme was.
Hi,
I have no idea whether this is really a memory leak (there seem to be more than one explanation for increase of memory usage) but I observe a similar behaviour of Sonic Pi in more complex applications I tried to create this year.
This is by no means hard data but just a quick test and observation concerning my Monome application to manipulate samples (short demo / code). Once I have started Sonic Pi the Ruby process uses ~32 MiB. When I start my application ('default' run mode without actually using any of the controls on the Monome) the memory usages increases according to the following table:
after Minute ... | MiB |
---|---|
0 | 32 |
1 | 165 |
2 | 285 |
3 | 447 |
4 | 532 |
5 | 685 |
After about 3 minutes Sonic Pi starts sending out "can't keep up" warning messages and then crashes. It might be the case that the continuously increasing use of memory hints to an underlying and more general problem.
System: Lenovo Thinkpad x230, i7, 4-core, 16 MB RAM, Linux Mint 18.1
@samaaron please take a look
Apologies but this is not a priority for me right now. However I would be happy to consider pull requests.
@samaaron
I have difficulty to run ruby memory tool against sonic pi on macOS --- probably because it doesn't run system ruby. If there's a thorough instruction on it maybe I can help.
@Wang-Yue feel free to share your process here in case any others of us have any ideas...
@ethancrawford this should be pretty straightforward to fix if people can access the right dev environment --- one just need to use memory tool monitoring libraries (such as memory_profiler
) to monitor the current process for a while. The leak is pretty massive so it should be fairly easy to find out what data is remaining in the memory that should have been cleaned. Unfortunately sonic pi does not use system ruby and provides no documentation on either how to use memory profilers or how to install custom libraries into the ruby implementation it provides in the package.
I am not really in a comfortable position to ask for help in this matter (because I can't contribute anything significant in the matter) but I wonder whether @Wang-Yue can be provided with the needed information, because he/she seems to be capable an willing to care for a fix (@Wang-Yue: which is what I understand from your previous comment).
The reason I am asking is selfish: I have an upcoming live coding performance an am messing around with projectM
to support the music with grafics. This works quite nicely but ... alas! ... after about 10 to 20 minutes of coding and running grafics SP consumes about 500 MB of RAM and finally just drops out and becomes quiet. Of course if I leave projectM
aside I have more (and enought) time but am lacking an important part of the performance for the uninitiated audience (which is an audience that sees live coding for the first time).
I am very willing to do testing if a fix could be made available.
@mbutz do you have a minimal code snippet that you can run which exposes this memory leak?
Perhaps @robmckinnon might be able to lend a hand here too?
I could probably run this example for 2 hours until the drop out; with more complex code I can reach the threshold within 10 or 20 minutes and my tracks are more complex than the following example code; of couse and as I said: running projectM
at the same time sort of provides the tipping point:
use_bpm 120
live_loop :noise do
use_synth :gnoise
use_synth_defaults attack: 0.25, sustain: 2, release: 12
with_fx :rbpf, centre: (scale :c3, :minor_pentatonic, num_octaves: 4).choose, pre_amp: 3, res: 0.975 do
with_fx :slicer, phase: (ring 0.35, 0.65, 0.85).choose do
with_fx :slicer, phase: 0.25, pulse_width: 0.8, smooth: 0.1, invert_wave: 1 do
with_fx :panslicer do
play :c1, amp: rrand(0, 2)
end
end
end
end
sleep 1
end
Trajectory on my machine of the Ruby
process:
after Minute ... | MiB |
---|---|
0 | 25.6 |
1 | 45.6 |
2 | 47.9 |
3 | 57.5 |
Ah... thanks a lot for taking action in that matter!
And if this matters: System: Lenovo Thinkpad x230, i7, 4-core, 16 MB RAM, Linux Mint 19.3
Another test run with one of my tracks, now running for quite a while (~50 minutes). The ruby process now needs about 428 MiB, last time Sonic Pi stopped as the process took about 500 MiB.
pid information
says the following:
ps -Flww -p 5612
ps -Flww -p 5612
F S UID PID PPID C PRI NI ADDR SZ WCHAN RSS PSR STIME TTY TIME
0 S marty 5612 5598 4 60 -20 - 622901 futex_ 357264 0 13:21 ? 00:00:54
Value of column CMD:
ruby --enable-frozen-string-literal -E utf-8 /home/marty/bin/sp32/sonic-pi/app/gui/qt/../../../app/server/ruby/bin/sonic-pi-server.rb -u 51235 51236 51237 51237 4560 4561 51238 51239 4562
I wonder if this is related to frozen strings and GC for Osc messages.
On 27 Feb 2020, at 12:51, G. Martin Butz notifications@github.com wrote:
Another test run with one of my tracks, now running for quite a while (~50 minutes). The ruby process now needs about 428 MiB, last time Sonic Pi stopped as the process took about 500 MiB.
pid information says the following:
ps -Flww -p 5612 ps -Flww -p 5612 F S UID PID PPID C PRI NI ADDR SZ WCHAN RSS PSR STIME TTY TIME 0 S marty 5612 5598 4 60 -20 - 622901 futex_ 357264 0 13:21 ? 00:00:54
Value of column CMD: ruby --enable-frozen-string-literal -E utf-8 /home/marty/bin/sp32/sonic-pi/app/gui/qt/../../../app/server/ruby/bin/sonic-pi-server.rb -u 51235 51236 51237 51237 4560 4561 51238 51239 4562
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/samaaron/sonic-pi/issues/2168?email_source=notifications&email_token=AAC2G55LQWFGPDR23IGHG3DRE6ZLZA5CNFSM4JRZ2QLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENEIDTI#issuecomment-591954381, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAC2G526O5WHD4NLTWFSDTTRE6ZLZANCNFSM4JRZ2QLA.
@xavriley what makes you think that? :-)
@samaaron I used memory_profiler to do memory profiling for that recent PR. For reference I've posted in that PR the profiling code in a comment.
I'll have a go at doing some profiling now based on the comments above.
I've put the memory_profiler
gem into a single file you can download.
Say you download memory_profiler.rb
to /Users/your_name
- then in Sonic Pi you can profile buffer with 1.upto(20)
loops like this:
load "/Users/your_name/memory_profiler.rb"
use_bpm 120
report = MemoryProfiler.report do
1.upto(20) do
use_synth :gnoise
use_synth_defaults attack: 0.25, sustain: 2, release: 12
with_fx :rbpf, centre: (scale :c3, :minor_pentatonic, num_octaves: 4).choose, pre_amp: 3, res: 0.975 do
with_fx :slicer, phase: (ring 0.35, 0.65, 0.85).choose do
with_fx :slicer, phase: 0.25, pulse_width: 0.8, smooth: 0.1, invert_wave: 1 do
with_fx :panslicer do
play :c1, amp: rrand(0, 2)
end
end
end
end
sleep 1
end
end
report.pretty_print(scale_bytes: true, to_file: "/Users/your_name/profile_buffer.txt")
Looks like this Thread.new
might be a memory hog in lib/sonicpi/lang/sound.rb
:
Thread.new do
__system_thread_locals.set(:sonic_pi_local_thread_group, :gc_kill_fx_synth)
Thread.current.priority = -10
if info
kill_delay = args_h[:kill_delay] || info.kill_delay(args_h) || 1
else
kill_delay = args_h[:kill_delay] || 1
end
subthreads.each do |st|
join_thread_and_subthreads(st)
end
tracker.block_until_finished
Kernel.sleep(kill_delay)
fx_container_group.kill(true)
end
In v3.1
, I get a memory_profiler report like this:
Total allocated: 89.58 MB (45115 objects)
Total retained: 82.19 MB (13597 objects)
allocated memory by file
-----------------------------------
80.12 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/lang/sound.rb
5.21 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb
1.13 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/runtime.rb
...
allocated memory by location
-----------------------------------
79.76 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/lang/sound.rb:2209
4.99 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:74
1.07 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/runtime.rb:951
...
allocated memory by class
-----------------------------------
80.97 MB Thread
5.65 MB String
1.60 MB Hash
...
allocated objects by file
-----------------------------------
11624 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/node.rb
5237 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb
3765 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/lang/sound.rb
...
allocated objects by location
-----------------------------------
2000 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:44
1572 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/node.rb:44
1500 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:74
...
allocated objects by class
-----------------------------------
15497 String
13279 Array
6250 Hash
1750 Thread::Mutex
1675 Proc
...
retained memory by file
-----------------------------------
79.94 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/lang/sound.rb
1.09 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/runtime.rb
353.83 kB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/node.rb
235.28 kB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/incomingevents.rb
...
retained memory by location
-----------------------------------
79.76 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/lang/sound.rb:2209
1.05 MB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/runtime.rb:951
235.20 kB /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/incomingevents.rb:125
...
retained memory by class
-----------------------------------
80.89 MB Thread
519.58 kB Hash
256.06 kB String
109.66 kB Thread::Mutex
...
retained objects by file
-----------------------------------
5588 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/node.rb
1777 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/lang/sound.rb
1227 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/incomingevents.rb
820 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/server.rb
...
retained objects by location
-----------------------------------
1225 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/incomingevents.rb:125
490 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/node.rb:44
490 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/node.rb:45
...
retained objects by class
-----------------------------------
3156 String
3006 Hash
1596 Array
1523 Thread::Mutex
...
Allocated String Report
-----------------------------------
960 "sched_ahead_time"
240 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/cueevent.rb:32
240 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/cueevent.rb:42
240 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/event_history.rb:244
240 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/event_history.rb:245
851 "i"
494 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:39
300 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:44
57 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_client.rb:29
765 "s"
700 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:44
57 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_client.rb:29
8 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/osc/udp_server.rb:39
720 "/cue/sched_ahead_time"
480 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/cueevent.rb:32
240 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/event_history.rb:237
...
Retained String Report
-----------------------------------
76 "reps"
76 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/server.rb:349
56 "phase"
56 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/server.rb:349
56 "rand_buf"
56 /Applications/Sonic Pi.app/app/server/ruby/lib/sonicpi/server.rb:349
...
@robmckinnon this is super useful, thanks. Looks like the fx garbage collecting thread might not always complete and be collected itself.
I’ll look at this in closer detail soon :-)
I've been able to reproduce these memory issues as well, and found a few hours ago that turning off "Log synths" in Prefs-->Editor-->Logging solves the memory leak for me. Worked for v3.1.0 w/ Ruby2.3, and v3.2.0-dev-8406d w/ Ruby2.6.5. Haven't tried it yet on today's official release. I'll see if memory_profiler
produces similar results.
Running on Linux Mint 18.3.
Hi,
"Log synths" in Prefs-->Editor-->Logging solves the memory leak for me
has no effect on my side concerning the increasing use of memory.
I've opened PR #2269 to cache resolving scale objects to help improve memory performance. Probably not the main cause of the issues reported above, but it does result in some improvement.
Hi there, I've just been running some tests locally and can't find any issues with the thread counts.
I've fired off many hundreds of nested FX and after a short while the thread count returns back to normal.
Perhaps there's some issue with memory being allocated to a thread which isn't being deallocated somehow. However, I'm seeing no evidence of this locally at this stage.
It should be said that I'm using Windows to test. Are all the issues that people are seeing on Linux?
FX is not the problem here. My test samples (such as the one I posted initially) have no FX at all but memory keeps leaking, as many other people have reported above. I'm not sure if it's a problem related to Windows. But both Linux (on a Pi) and macOS have the issue. I'm using 3.2.0
Well, I do not see many other ones but I can say, that at least for me this is a critical issue concerning live performances with a somehow ambitious setup - because once you reach some threshold the behaviour of Sonic Pi resp. SuperCollider becomes unpredictable.
I would be really interested if others can confirm this issue.
I also think that this is not an issue depending or especially being caused by the use of FX; my initial example is code triggered by a Monome and only uses the FX :sound_out_stereo and :record.
I only checked on Linux but I could (at the weekend) check with Sonic Pi 3.1 on OS X 10.11.6 if this helps.
Help locating this would definitely be appreciated. I'm running out of ideas of where to look.
I memory profiled the code sample in Wang-Yue's first post to this issue.
Retained memory seems to increase the longer things are run.
retained memory by file
-----------------------------------
404.88 kB /Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/core.rb
199.22 kB /Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/lib/sonicpi/runtime.rb
109.44 kB /Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/lib/sonicpi/node.rb
retained memory by location
-----------------------------------
140.29 kB /Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/core.rb:87
140.29 kB /Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/core.rb:88
123.90 kB /Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/core.rb:94
@samaaron In core.rb
__sync_path
seems to create strings that are in retained memory.
def __sync_path(s)
if s.is_a?(Symbol)
return "/{cue,set,live_loop}/#{__cue_path_segment(s)}".freeze
end
s = s.to_s
if s.start_with?('/')
s = String.new("#{s}") # <- Why do we need to create new string here? Looks like twice?
else
s = String.new("/cue/#{s}") # <- Do `s` values repeat? Could this be cached, keyed by `s`?
end
s.freeze
s
end
^ Opps, I was looking at the wrong core.rb
file there.
Interesting.
Nothing here seems to be explicitly retaining the strings and therefore keeping them in memory. Unless .freeze
is doing exactly that? Reading around, it seems that .freeze
also caches the string in addition from stopping it from being mutable. I wonder if this is the problem?
I'm pretty sure those String.new
are unnecessary but they should just be creating extra allocations, which eventually should be GCd.
Hi,
I can confirm that also on Mac OS X (10.11.6) using Sonic Pi 3.1 the Ruby process is continuessly needing more RAM. I have a rather old iMac (2.66 GHz Intel Core Duo, 8 MB RAM).
This is my test code:
live_loop :mem do
with_synth_defaults release: 0.125 do
at (line 0, 4, steps: 32) do
play (scale :c, :major_pentatonic).choose
play (scale :d, :major_pentatonic).choose
end
end
sleep 4
end
And here are the results (Ruby Prozess, used RAM in MB):
after min. | MB |
---|---|
0 | 34.6 |
1 | 54.7 |
2 | 76.1 |
3 | 93.7 |
4 | 110.8 |
5 | 137.5 |
6 | 150.1 |
@mbutz - thanks. Although I don't think anyone is doubting there's a memory leak somewhere.
It's just that I'm not sure where it is and where to look and right now my priority is currently on getting things to boot more reliably on Windows and also to figure out code signing.
As mentioned before, any help with this would be hugely appreciated.
I've worked on this memory leak thing solidly for 3 days now.
I've removed and reworked whole sections of code, removing a whole dependency and re-implementing the core immutable data structures.
I've also pinpointed 3 leaks, 2 of which I appear to have fixed, one I haven't (something to do with in_thread
) but I've massively reduced its impact.
Provided you don't place in_thread
in a very tight loop and therefore call it many times a second, the leak has dramatically slowed down. Hopefully this can buy us some time until we figure out where in_thread
is secretly stashing the memory! There's probably other minor leaks elsewhere to be found.
I'm off on holiday for a few days now, but will get back on it when I return. As always, any help would be appreciated!
Hi @samaaron , thanks a lot for the hard work. While rehearsing for my upcoming gig I've just had the experience that SuperCollider crashed (happened a few times under a certain amount of system load with my current 3.2 dev). I am not at all sure that this has something to do with this issue but ... I will try to linux-compile the current developement version and check if there's a change (which I would massively appreciate). Hope you'll have some relaxing days!
Weird that SuperCollider crashes! If you’re able to find a way to reliably reproduce it, that would be amazing. Are you using their latest release?
Yeah. That is weird.
Actually my setup also involves also Carla and some audio plugins. This did work quite reliably (I used this for the Sonoj performance, so repeatedly since 2018) with, I think, SP 3.1.
I am now using 3.2.0-dev I compiled a few months ago (SC 3.9.1). What makes it even more complicated are my attempts to add some visualization (projectM). So my guess is, that from time to time I am reaching some critical threshold. But again: I have never had a SuperCollider crash before while Sonic Pi is still running.
At the moment I don't seem to have a reproducable scenario so it only happens occasionally - nevertheless I think I will have to skip the visualisation for the gig, it is just to dangerous (I can live with a growing number of xruns, which kind of function as warnings but a crash is another thing).
I let you know if there is reproducable testcase
Compiled 3.2 current developement branch for Linux.
First tests suggest: Much, much, much better; memory for Ruby process only very slightly increases compared to where it previously went. But I still have to do some testing ...
Tried the 3.2.1 Mac binary just released. significantly better! though slowly leaking, it's very slow and the program is now usable. Huge kudos to Sam for fixing most of the leaks! Haven't tried it in RPi yet as the upstream version was still 3.1 there. Any plans to upgrade the apt package?
See here for a new version for Raspberry Pi prepared by Robin Newman: https://in-thread.sonic-pi.net/t/sonic-pi-3-2-1-released-for-mac-pc-and-raspberry-pi/3566
@wang
Tried the 3.2.1 Mac binary just released. significantly better! though slowly leaking, it's very slow and the program is now usable.
Huge kudos to Sam for fixing most of the leaks!
Memory usage going up is normal after a fresh start. For me it goes up gradually for 5 mins or so and then stabilises.
Are you seeing it continually rise for a long sustained period?
That's interesting to know. I also notice a slow increase of memory use. Will check if it stops after a while.
A slow "leak" is to be expected for a period as it is the caches filling up.
I recently tried to run sonic-pi v3.1 on my rpi with 1 gb memory and frequently run into throttle (if given swap) or crash because of running out of memory. My file has nothing special and no increasing memory allocation at all. I noticed the ruby process is eating more and more memory throughout the time.
I tried the shortest sample below and monitor the ruby process for a few minutes and found increased memory as well:
I notice the problem occurs on my mac as well so it's not platform specific. I didn't notice it before as it has plenty of memory.