In Ruby, if I declare a lambda function inside a loop, will it clean up properly after each iteration?
I have something like this:
for i in 1..100000
template = GetTemplate(i)
set_setting_lam = lambda do |setting|
(...) # Would prefer not to duplicate the code for the loops below
template.setting = setting
end
for setting in settingArray
set_setting_lam.call(setting)
end
for setting in settingList
set_setting_lam.call(setting)
end
end
Will this generate 100,000 set_setting_lam
objects, or will it clean up after each iteration?
source to share
A lambda is an object like any other object.
Of course, if you create an object in a loop that runs 100,000 times, 100,000 objects will be created. This does not apply to lambdas, it applies to all objects. And of course, as soon as an object is no longer available, it becomes garbage collection. Again, this is not the case for lambdas, this is for all objects.
The system decides when to run the garbage collector and how many and what objects to collect. If you are running out of memory, the garbage collector might not work at all! Even if the garbage collector does eventually, it is impossible to tell when it will. And even when it works, there is no guarantee that it will collect all the suitable objects, and there is no way to tell which objects it will collect.
That it's all about automatic memory management: it's automatic!
source to share
It will create objects and they will not be cleaned up after each iteration based on this:
object_ids = []
1.upto(5) { |i| object_ids << lambda{ i }.object_id }
object_ids.each do |object_id|
puts "#{ ObjectSpace._id2ref(object_id) } - #{ ObjectSpace._id2ref(object_id).call }"
end
#<Proc:0x007fae509c7380@test1.rb:2 (lambda)> - 1
#<Proc:0x007fae509c7330@test1.rb:2 (lambda)> - 2
#<Proc:0x007fae509c72e0@test1.rb:2 (lambda)> - 3
#<Proc:0x007fae509c7290@test1.rb:2 (lambda)> - 4
#<Proc:0x007fae509c7240@test1.rb:2 (lambda)> - 5
UPD
It will start garbage collection after a while since 1000 888 objects were left in memory after the loop for me.
source to share
After playing around with @Rustam A. Gasanov's answer, the answer is no: Ruby's garbage collector will start cleaning it up eventually, but not after every iteration.
Duration:
object_ids = []
1.upto(1000) { |i| object_ids << lambda{ i }.object_id }
object_ids.each_with_index do |object_id, index|
puts index
puts "#{ ObjectSpace._id2ref(object_id) } - #{ ObjectSpace._id2ref(object_id).call }"
end
results in _id2ref': 0x13a2c74 is recycled object (RangeError)
or something like that after a while (for me it gave an error at index 160).
source to share