JezK
Edit File: thread_local_memory_usage.rb
#!/usr/bin/env ruby #$: << File.expand_path('../../lib', __FILE__) $DEBUG_TLV = true require 'concurrent' require 'concurrent/atomic/thread_local_var' require 'benchmark' require 'thread' include Concurrent # if we hold on to vars, but threads die, space used for TLVs should be recovered def test_thread_gc(vars) threads = 500.times.collect do Thread.new do vars.each do |var| var.value = 1 end end end threads.each(&:join) end puts "BEFORE THREAD GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" vars = 500.times.collect { ThreadLocalVar.new(0) } 200.times do test_thread_gc(vars) GC.start end puts "AFTER THREAD GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" # if we hold on to threads, but drop TLVs, space used should be reused by allocated TLVs def tlv_gc_test_loop(queue) while true var = queue.pop return if var.nil? var.value = 1 end end def test_tlv_gc(queues) 500.times do var = ThreadLocalVar.new(0) queues.each { |q| q << var } end end puts puts "BEFORE TLV GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}" queues = 500.times.collect { Queue.new } threads = queues.map do |queue| Thread.new do tlv_gc_test_loop(queue) end end 200.times do test_tlv_gc(queues) GC.start end queues.each { |q| q << nil } threads.each(&:join) puts "AFTER TLV GC TEST:" puts "Ruby heap pages: #{GC.stat[:heap_length]}, Other malloc'd bytes: #{GC.stat[:malloc_increase]}"