Ruby 2.2 的增量垃圾收集机制(3)

我们通过“进入”和“离开”事件计量中断时间。增量垃圾收集(增量标记和延迟清理)引入中断标记和清理阶段。“进入“是”进入垃圾清理“事件,”离开“是”离开垃圾清理“事件。 

下图显示了当前增量垃圾收集器的事件时间。

Ruby 2.2 的增量垃圾收集机制

垃圾收集器事件

我们可以计量每一个事件的当前时间(在 Linux 上当前时间是通过 gettimeofday() 获得)。所以我们可以通过“进入”和“离开”事件计量垃圾收集器的中断时间。

我使用 ko1-test-app 做为我们中断时间的基准。ko1-test-app 是我们的一个英雄“Aaron Patterson"为我写的一个小的 rails app

为了使用 gc_tracer,我添加了一条命名为“test_gc_tracer”的规则,如下:

diff --git a/perf.rake b/perf.rake
index f336e33..7f4f1bd 100644
--- a/perf.rake
+++ b/perf.rake
@@ -54,7 +54,7 @@ def do_test_task app
  body.close
 end
 
-task :test do
+def test_run
  app = Ko1TestApp::Application.instance
  app.app
 
@@ -67,6 +67,22 @@ task :test do
  }
 end
 
+task :test do
+  test_run
+end
+
+task :test_gc_tracer do
+  require 'gc_tracer'
+  require 'pp'
+  pp GC.stat
+  file = "log.#{Process.pid}"
+  GC::Tracer.start_logging(file, events: %i(enter exit), gc_stat: false) do
+ test_run
+  end
+  pp GC.stat
+  puts "GC tracer log: #{file}"
+end
+
 task :once do
  app = Ko1TestApp::Application.instance
  app.app

运行 bundle exec rake test_gc_tracer KO1TEST_CNT=30000。我们通过数值“30000”指定模拟30,000个请求。我们可以在文件“log.xxxx”里得到结果(xxxx是程序的进程ID)。文件如下

type  tick  major_by      gc_by  have_finalizer  immediate_sweep state
enter  1419489706840147      0    newobj  0    0    sweeping
exit  1419489706840157      0    newobj  0    0    sweeping
enter  1419489706840184      0    newobj  0    0    sweeping
exit  1419489706840195      0    newobj  0    0    sweeping
enter  1419489706840306      0    newobj  0    0    sweeping
exit  1419489706840313      0    newobj  0    0    sweeping
enter  1419489706840612      0    newobj  0    0    sweeping
...

在我的环境下,这里有 1,142,907 行。

“type”列是事件类型,tick 是当前时间(gettimeofday()的输出结果,epoc总时间,单位是毫秒)。通过这些信息我们可以获取垃圾收集器的中断时间。通过前两行我们可以计算出中断时间为10 微秒 (1419489706840157 - 1419489706840147)。

以下小脚本显示每次中断时间。

enter_tick = 0
open(ARGV.shift){|f|
  f.each_line{|line|
  e, tick, * = line.split(/\s/)
  case e
  when 'enter'
    enter_tick = tick.to_i
  when 'exit'
    st = tick.to_i - enter_tick
    puts st if st > 100 # over 100 us
  else
    # puts line
  end
  }
}

这里有很多行,这个脚本打印了 100 微秒内的中断次数。

下图显示了统计结果

Ruby 2.2 的增量垃圾收集机制

在分代垃圾收集器中产生了7个较大的中断时间,他们应该是由“major GC”产生的。最大中断时间大概15毫秒(15Kus),不管怎样,增量垃圾收集器减少了最大中断时间(差不多2ms(2Kus)),太好了。

总结

Ruby 2.2 通过引入增量垃圾收集算法缩短了垃圾收集的中断时间。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/db34a274cedad14083732a0082cc5922.html