-
-
Notifications
You must be signed in to change notification settings - Fork 925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ivar creation with instance_eval triggers lookup hell in other instances #3859
Comments
The main problem here is that The fact that it degrades could mean there's a leak, or it could just be reflecting the fact that a very large amount of garbage is being created and forcing the JVM GC to work very hard. That's worth investigating. FWIW, |
Ok, so I suspect the degradation is due to having a new instance variable name every time. JRuby's instance variable logic (and I believe MRI's is similar) maintains a mapping from name to offset in the object's nearest non-singleton class. In this case, that's So, there's a small, slow leak in the variable table that would be hard to eliminate, but the main degradation issue is that the actual array of variables get larger and larger. If your code is doing this, with a completely new ivar name every time, that's probably not a great pattern for any implementation. We are somewhat limited in how we can map those variables, and like I say I believe MRI does it mostly the same way. |
@headius I confirm that using class A
def initialize(i)
instance_variable_set("@a#{i}", i)
end
end
i = 1
start = Time.now
while true
i += 1
A.new(i)
if (i % 1000) == 0
puts "#{i} last iteration took #{Time.now - start}"
start = Time.now
end
end
MRI behaves similarly. Agreed that the pattern we use here is not good, we should refactor that. |
Thanks for the explanation @headius, it's definitely a bad pattern and we're changing it. I think we can close this issue since it's a characteristic of Ruby's object model? |
@jsvd There's no standard Ruby way, but in JRuby, you can do this: class A
def initialize(i)
instance_eval "@var#{i} = 1"
end
end
10.times {|i| A.new(i)}
puts JRuby.reference(A).variable_table_manager.variable_names.to_a This outputs The justification for not managing an instance variable table on the singleton class is that we'd have to always duplicate the non-singleton class's list into the singleton anyway, since any one of the variables the regular class has seen might get assigned in the singleton at some time in the future. An alternative mechanism might be to manage instance variable names like we manage methods, via the class hierarchy. However, this would mean having to search that hierarchy frequently and I don't currently know how we'd coordinate monotonically-increasing offsets across a chain of ancestors. Interestingly, Rubinius does not appear to have this issue for dynamically-assigned variables, but it may be dumping those into a (much slower) hash table on the object rather than assigning an offset to every new variable. I've pinged @evanphx to learn more. |
@jsvd Oh, and thanks :-) I will close this issue for now since I don't see us changing how we manage ivars right now. |
Hi!
Recently a huge slowdown in logstash has been traced to different instances of our
LogStash::Pipeline
having instance variables with different names between each other. And while these instances are being garbage collected, something is left behind, causing dramatic CPU overhead.The following script illustrates the scenario:
Obviously there's an argument as to "WHY WOULD YOU DO THAT" but, that aside, in my perception of the ruby object model, each instance_eval creates the ivar on a single instance, so it's perfectly isolated from the next (instance).
To corroborate with this, I cannot programmatically find a class or object in ruby that shows me a build up/list of "@v_*" instance variables, each instance of A only shows a single ivar.
However, we can see that there's a big impact of their creation:
I should note that we can see a speed degradation in MRI as well, but it's an order of magnitude slower for jruby.
Any thoughts on why this happens?
The text was updated successfully, but these errors were encountered: