-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
Environment
Running jruby 9.1.7.0 (2.3.1) 2017-01-11 68056ae Java HotSpot(TM) 64-Bit Server VM 25.111-b14 on 1.8.0_111-b14 +jit [linux-x86_64] on Linux maruchan 4.9.0-11-generic #12-Ubuntu SMP Mon Dec 12 16:18:23 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux.
Expected Behavior
Example code:
class Dummy
def initialize
@payload = Array.new(100000)
end
def next
@next = Dummy.new
end
end
class Test
def self.test
dummy = Dummy.new
iterations = 0
while true
dummy = dummy.next
iterations += 1
puts "ran iteration #{iterations}"
GC.start if iterations % 10 == 0
sleep if iterations == 200 && ENV['PAUSE_AFTER_ITERATIONS'] == '1'
end
end
end
Test.testOn MRI this code seems to behave correctly (e.g. it does not leak memory) and I can get up to hundreds of thousands of iterations with < 16MB memory being used.
Actual Behavior
Running with jruby:
$ jruby -J-Xmx200m leak_testcase.rb
ran iteration 1
ran iteration 2
...
ran iteration 466
ran iteration 467
Error: Your application used more memory than the safety cap of 200M.
Specify -J-Xmx####M to increase it (#### = cap size in MB).
Specify -w for full java.lang.OutOfMemoryError: Java heap space stack trace
By pausing after a few iterations and looking at a memory dump (with PAUSE_AFTER_ITERATIONS=1 jruby -J-Xmx200m leak_testcase.rb), we can see the following:
E.g. all instances of Dummy are still alive, whereas looking at the code we are creating a linked list but we never keep references to previous nodes so we should only have a single instance visible in memory.
Looking at one of the instances, we see that they are being kept alive due to a reference stored on the stack:
and by asking for a list of stack references we see that there are two Dummy instances being referred to from the stack, not one as expected.
It seems like the code generating is leaving the first dummy instance referenced on the stack and thus causing the memory leak as the whole list will be kept in memory, rather than just the last element.
We (@Talkdesk) hit this in production as we were iterating a large collection using hyperclient and thus were hitting memory limits even though we were doing it a slice at a time.


