<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>jackxu (jackxu)</title>
    <link>https://ruby-china.org/jackxu</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>关于 Ruby 内存使用的一些优化和探索</title>
      <description>&lt;p&gt;前段时间写了一个 benchmark 来测试下最近写的一个服务的 api，发现随着访问次数的增加，使用内存在慢慢上升，在上升到一定量之后，使用的内存基本稳定了下来。当然除了本身是一个图片上传的服务，需要消耗内存相比一般的 request 更多点之外，还是想弄明白下 ruby 内存是怎样一种回收和使用机制，为什么短时间内 Ruby 进程消耗的内存会增加如此之快，Ruby 内部的 Garbage Collect(简称 GC) 到底多久回收一次垃圾，到底怎么个回收流程，到底能把消耗的内存变小多少。于是便查阅了下 GC 相关的一些文档和内存跟踪的一些使用工具，实践并总结了下可以优化内存的一些方法，希望能对大家有所帮助。本文中使用的 Ruby 环境是 Ruby 2.1.4 + Rails 4.2.1, 后端 app server 使用的是 Unicorn, 运行在 2 台 AWS t2.large 上面，以及为了测试方便的本地 mac 机器（OS X 10.10.1）。由于本人经验和认知有限，若有失实之处，还望指正。也希望大家能畅所欲言，探讨并分享下自己的理解。&lt;/p&gt;
&lt;h2 id="app server 方面着手"&gt;app server 方面着手&lt;/h2&gt;
&lt;p&gt;首先来看下测试开始前的状态 Unicorn 的内存使用状态，通过下面的命令查来看下占用内存最多的 15 个应用进程（在此隐去真实的服务器和项目相关信息，但测试数据均为实测数据）。你可以发现，这这里消耗内存最多的是我们的 Unicorn 应用进程，我在 Unicorn 配置文件里，每台机器配置了 10 个 worker_processes（为了让测试的效果更为拔群)。每个 Unicorn 进程大概占用了 2% 左右的内存，再加上 master 进程，总共占用了 21% 的内存总量。最初始的每个 Unicorn 所使用的内存量和你工程本身的大小有关系。在一个空的 Rails 工程中（本文使用 Rails 4.2.1 测试），占用了 70 多 m 左右的内存。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[user001@xxxx-web01 ~]$ ps -eo pmem,pcpu,vsize,pid,cmd | sort -k 1 -nr | head -15
 2.0  0.0 545968 25897 unicorn_rails master -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26124 unicorn_rails worker[9] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26119 unicorn_rails worker[8] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26116 unicorn_rails worker[7] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26111 unicorn_rails worker[6] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26104 unicorn_rails worker[5] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26100 unicorn_rails worker[4] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26098 unicorn_rails worker[3] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26092 unicorn_rails worker[2] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26090 unicorn_rails worker[1] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 1.9  0.0 545968 26088 unicorn_rails worker[0] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 0.6  0.0 1243972 2447 /opt/ds_agent/ds_agent -w /var/opt/ds_agent
 0.1  0.0 155540 17719 /usr/bin/perl -wT /usr/sbin/munin-node
 0.0  0.0 243976  2427 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面我们来运行下 benchmark，benchmark 采用了多线程的方式来访问我的 api 服务，在近三分钟的时间内，总共上传了 1500 张图片并做了相关的人脸识别处理，再来看下我们的内存占用前 15 位的内存使用状况。我们能够发现，Unicorn 进程的内存除了 master 进程之外，各个 workers 都和以前相比有了较大的增加。从最低的 1.9% 增加到了 3.6% 左右。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[user001@ipsa-web01 ~]$ ps -eo pmem,pcpu,vsize,pid,cmd | sort -k 1 -nr | head -15
 3.6  0.0 675644 26119 unicorn_rails worker[8] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 671416 26090 unicorn_rails worker[1] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 669144 26098 unicorn_rails worker[3] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.5  0.0 668872 26092 unicorn_rails worker[2] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.5  0.0 667220 26100 unicorn_rails worker[4] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.5  0.0 663384 26116 unicorn_rails worker[7] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.4  0.0 661892 26088 unicorn_rails worker[0] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.3  0.0 650784 26111 unicorn_rails worker[6] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.3  0.0 645692 26124 unicorn_rails worker[9] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.2  0.0 647860 26104 unicorn_rails worker[5] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 2.0  0.0 545968 25897 unicorn_rails master -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 0.6  0.0 1243972 2447 /opt/ds_agent/ds_agent -w /var/opt/ds_agent
 0.1  0.0 155540 17719 /usr/bin/perl -wT /usr/sbin/munin-node
 0.0  0.0 243976  2427 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在此基础上我再一次上传了 1500 张图片，下面是跑完之后各个进程的内存使用情况。我们发现这次各个 Unicorn worker 使用内存只是略有增加，但已经远小于上一次跑 benchmark 时的内存增幅了。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[user001@ipsa-web01 ~]$ ps -eo pmem,pcpu,vsize,pid,cmd | sort -k 1 -nr | head -15 
 4.1  0.0 709428 26098 unicorn_rails worker[3] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.8  0.0 689600 26116 unicorn_rails worker[7] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.7  0.0 691624 26104 unicorn_rails worker[5] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 676696 26088 unicorn_rails worker[0] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 675644 26119 unicorn_rails worker[8] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 671520 26100 unicorn_rails worker[4] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 671416 26090 unicorn_rails worker[1] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 669372 26124 unicorn_rails worker[9] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.6  0.0 666984 26092 unicorn_rails worker[2] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 3.2  0.0 651596 26111 unicorn_rails worker[6] -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 2.0  0.0 545968 25897 unicorn_rails master -c /home/app/image_test/production/current/config/unicorn.rb -E production -D
 0.6  0.0 1243972 2447 /opt/ds_agent/ds_agent -w /var/opt/ds_agent
 0.1  0.0 155540 17719 /usr/bin/perl -wT /usr/sbin/munin-node
 0.0  0.0 243976  2427 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然而，可以发现的是内存占用最大的进程从已经从最初的 1.9% 到了 4.1%，如果继续这样下去的话，每个 Unicorn worker 使用的内存可能会越来越大（事实上也是如此，在此就不再把相关的运行结果列出来了）。这个时候，如果我们能够限制每个 Unicorn worker 的大小，总体来说就能控制了 Unicorn 所占用的总内存大小。这个时候，我们可以利用一个叫&lt;a href="https://github.com/kzk/unicorn-worker-killer" rel="nofollow" target="_blank" title=""&gt;unicorn-woker-killer&lt;/a&gt; 的工具来达到这一目的。它可以设置你的 request 个数达到设定值的时候杀死 worker，也可以在你 worker 内存达到设定值的时候杀死这个 worker。它的优点在于在杀死 unicorn woker 的时候并不会影响到你的 request 请求。&lt;/p&gt;

&lt;p&gt;这个 gem 的使用方法非常简单，首先你的 Gemfile 里面（最好放在&lt;code&gt;group :production&lt;/code&gt;下面）设置如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:production&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;unicorn&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;killer&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在你 Rails 应用的 config.ru 文件中，&lt;code&gt;require ::File.expand_path('../config/environment', __FILE__)&lt;/code&gt;之前，加入如下代码。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'unicorn/worker_killer'&lt;/span&gt; 
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Unicorn&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;WorkerKiller&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Oom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;290&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 &lt;code&gt;Unicorn::WorkerKiller::Oom&lt;/code&gt;指定的是内存，在这里设定 worker 使用内存达到 260M 和 290M 之间的值某个值时，就把这个 worker 杀死。注意这里某个值指的是 260M 到 290M 之间的一个随机值。（另：&lt;code&gt;unicorn-worker-killer&lt;/code&gt;也可以通过设置 max 的 request 个数来杀死 worker，大家可以根据自己的需要设定，在这里就暂时不介绍）&lt;/p&gt;

&lt;p&gt;设置好了之后，我们再来一发（上传 1500 张图片并处理），看看占用前 15 的进程有什么变化。（注意：由于设置好了需要重启 Unicorn，为了观察进程的变化，上面的设置我试验前就设置并部署好了）&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[user001@xxxx-web01 ~]$ ps -eo pmem,pcpu,vsize,pid,cmd | sort -k 1 -nr | head -15
 4.1  0.0 709428 26098 unicorn_rails worker[3] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.9  0.0 693076 26092 unicorn_rails worker[2] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.8  0.0 699880 26124 unicorn_rails worker[9] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.8  0.0 691624 26104 unicorn_rails worker[5] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.8  0.0 689600 26116 unicorn_rails worker[7] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.6  0.0 676696 26088 unicorn_rails worker[0] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.6  0.0 675644 26119 unicorn_rails worker[8] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.6  0.0 671520 26100 unicorn_rails worker[4] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.1  0.0 634372 26111 unicorn_rails worker[6] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 2.9  1.2 619084 23679 unicorn_rails worker[1] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 2.0  0.0 545968 25897 unicorn_rails master -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 0.6  0.0 1243972 2447 /opt/ds_agent/ds_agent -w /var/opt/ds_agent
 0.1  0.0 155540 17719 /usr/bin/perl -wT /usr/sbin/munin-node
 0.0  0.0 243976  2427 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对比下上一次前 15 位的进程，我们发现一个变化，woker[1] 的 pid 发生了改变，并且由原来的内存使用 3.6% 变为 2.9%，这点说明，&lt;code&gt;unicorn-woker-killer&lt;/code&gt;确实在限制各个 unicorn worker 大小的时候起到了作用，并在总使用内存的控制上起到了作用。当然，通过&lt;code&gt;unicorn-worker-killer&lt;/code&gt;方式可以做到杀死 worker，也就可以通过 batch 的方式让他自动重启了，比如在 cron job 中根据时间来定期杀死 worker 进程，但这需要根据你的实际需要而定。&lt;/p&gt;

&lt;p&gt;探讨完工具&lt;code&gt;unicorn-worker-killer&lt;/code&gt;的使用，你可能也会发现，这 Unicorn worker 的数目也太多了。为了实验的效果更为拔群，我在每台机器上启动了 10 个 worker 来处理 request。但实际使用的时候，你到底要需要几个 Unicorn worker 是你的访问量和请求处理的复杂度来决定的。当然理想的情况下，我希望有大概 20%-30%（这个数据只是我自己的一个喜好，并不代表标准）左右的 worker 处于比较空闲的状态，以便高峰到来的时候能够进行处理。那么，我们将 Unicorn 的 worker_processes 设置为 6，再次运行下 benchmark，来看下 Unicorn 使用内存的情况。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[user001@ipsa-web01 ~]$ ps ax -eo pmem,pcpu,pid,cmd | sort -k 1 -nr | head -15
 4.0  0.0  3947 unicorn_rails worker[5] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.6  0.0  3932 unicorn_rails worker[1] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.5  0.0  3938 unicorn_rails worker[3] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.5  0.0  3936 unicorn_rails worker[2] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.5  0.0  3930 unicorn_rails worker[0] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 3.3  0.0  3941 unicorn_rails worker[4] -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 2.0  0.0  3743 unicorn_rails master -c /home/app/ipsa/production/current/config/unicorn.rb -E production -D
 0.5  0.0  2130 /opt/ds_agent/ds_agent -w /var/opt/ds_agent
 0.1  0.0  2555 /usr/bin/perl -wT /usr/sbin/munin-node
 0.0  0.1  6824 nginx: worker process
 0.0  0.0 24457 [kworker/1:2]
 0.0  0.0 16735 [kworker/0:0]
 0.0  0.0 15440 [kworker/0:1H]
 0.0  0.0  7699 head -15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的结果可以看到，虽然单个的 Unicorn worker 占用内存没有多大变化，但整体的 Unicorn 进程个数从 10 到 6，使用的总内存已经减少不小了。在使用前后两次 benchmark 的时候，记录了下运行时间，10 个 worker 的时候比 6 个 worker 的时候快 10 几秒，而不是第一次整体运行时间的 2/5，这说明其实最开始 Unicorn worker 是过多的，远超出我们的实际需要。由此可见，在满足访问需求的合理的前提下，尽量减少 Unicorn worker 的个数，能较大程度的减少你内存的使用。&lt;/p&gt;
&lt;h2 id="Ruby的GC和Rails方面着手"&gt;Ruby 的 GC 和 Rails 方面着手&lt;/h2&gt;
&lt;p&gt;通过上面 Unicorn 的方式来改变内存使用的大小，虽然达到了效果，但还是没明白内存使用量变化究竟是怎么一回事。Unicorn 的内存使用中，除了最开始访问的时候需要将相关的代码加载入内存，程序内构建的对象所占用的内存外（包括代码，中间变量及请求数据和返回数据），以及一部分 cache 之外及程序可能存在 memory leak 之外，是什么东西的增加，让一个 worker 从 100 多 m 变到最大 300m 左右？Ruby 的垃圾回收是怎么工作的，怎么去判断他在正常工作呢？好在 Ruby 给我们提供了一些比较直观的 module。它们就是&lt;a href="http://ruby-doc.org/core-2.2.0/GC.html" rel="nofollow" target="_blank" title=""&gt;GC&lt;/a&gt; 和&lt;a href="http://ruby-doc.org/core-2.2.0/ObjectSpace.html" rel="nofollow" target="_blank" title=""&gt;ObjectSpace&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;GC 提供了一些方法来了解 Ruby 的垃圾回收机制，ObjectSpace 则可以允许你查看现行状态下 living  objects 的状态。在 Ruby 的 GC 中，采用了一种叫 mark and sweep 的机制来回收垃圾。比较简便的来说，GC 在回收垃圾的时候，它会从根对象开始遍历内存中的对象，如果能够 reach 那个对象，就 mark 下，最后再检查下所有的对象，看那些对象没有被 mark，就回收这些对象（即 sweep）。此处有一幅较为清楚的图来表现这一过程 (&lt;a href="http://engineering.heroku.com/blogs/2015-02-04-incremental-gc/" rel="nofollow" target="_blank" title=""&gt;来源&lt;/a&gt;）&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/8affb529d18cb4fbc14642f200e2b9ff.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;通过这一过程，能够大致的有个形象的认知，但是并不明了 Ruby 对象在内存中是怎样存在的。在 MRI 中，Ruby 有这样一种类似于 C 语言中结构体的结构，Ruby 中称其为 RValue 结构，对象被存放在这个结构体中。在结构体中，除了对象之外，还附有一个 flag，也就是我们前面所讲的在 mark-and-sweep 机制被 mark 时要使用的 flag。内存中，Ruby 将许多这样的 RValue 结构体组织在一种被称为 heap 的数组里面。在一个进程当中，有许多这样的 heap 数组存在。每个 RValue 结构体的大小是 40bytes，这也预示着这里不能存放较大的对象，故 Ruby 将一些较小的常用的 String, Array 或 Hash 等对象存放在此处。（详情可参考&lt;a href="http://patshaughnessy.net/2012/3/23/why-you-should-be-excited-about-garbage-collection-in-ruby-2-0" rel="nofollow" target="_blank" title=""&gt;此文&lt;/a&gt;） &lt;/p&gt;

&lt;p&gt;有了上面的一些基本的了解，我们就可以通过小小的实验来查看下 GC 的运行机制了。在 GC module 中，为我们提供了一个&lt;code&gt;GC.stat&lt;/code&gt;方法来查看 GC 的状态。
下面在 irb 中来看看 GC 为我们提供了那些状态。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;➜&lt;/span&gt;  &lt;span class="o"&gt;~&lt;/span&gt;  &lt;span class="n"&gt;irb&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;simple&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stat&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="ss"&gt;:count&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="ss"&gt;:heap_used&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;261&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="ss"&gt;:heap_length&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;261&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;:heap_increment&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;106167&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12646&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;261&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;891605&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;785438&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;312768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;850&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="ss"&gt;:old_object&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;73265&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;82108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1036768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16777216&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;GC.stat&lt;/code&gt;给我们返回了一个 Hash，其中 count 所指向的值是 GC 运行的次数，它是由 minor_gc_count + major_gc_count（29 + 5 = 34) 来组成的。其中 minor_gc_count 指的是 GC 进行的一次小型的回收，而 major_gc_count 则是 GC 进行的是一次 full 垃圾回收。之所以这样区分开来，是因为每次 minor 回收所需要使用的时间远小于 major 使用的时间。每次进行 GC 回收的时候，会消耗很大的资源和性能。根据情况进行 minor 回收能够较好的实现性能的提升。head_used 指代的是当前正在使用的 heap 的个数，而 heap_live_slot 指的是在 GC 运行以来，还存活的对象的个数。在此处，一个 heap 可以简单的理解为有很多个 slot 来组成，而 heap_free_slot 就是原来已经被分配的 slot，但是里面的对象已经被释放了，可以用来存放新的对象的 slot 的个数。&lt;/p&gt;

&lt;p&gt;根据上面的一些概念，我们来做一个简单的实验。写一个简单的 script，来测试下 GC 运行的状态和内存使用的情况。script 如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;report&lt;/span&gt;
 &lt;span class="mi"&gt;2&lt;/span&gt;   &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Memory '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sb"&gt;`ps ax -o pid,rss | grep -E "^[[:space:]]*&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vg"&gt;$$&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;"`&lt;/span&gt;
 &lt;span class="mi"&gt;3&lt;/span&gt;         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:to_i&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'KB'&lt;/span&gt;
 &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
 &lt;span class="mi"&gt;5&lt;/span&gt;
 &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;
 &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stat&lt;/span&gt;
 &lt;span class="mi"&gt;8&lt;/span&gt;
 &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="n"&gt;long_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10_000_000&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;
&lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stat&lt;/span&gt;
&lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="mi"&gt;13&lt;/span&gt; &lt;span class="n"&gt;long_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="no"&gt;ObjectSpace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;garbage_collect&lt;/span&gt;
&lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;
&lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stat&lt;/span&gt;
&lt;span class="mi"&gt;17&lt;/span&gt;
&lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;
&lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stat&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来看下运行的结果：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ruby -v memory_profiler.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;p265&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2014&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="mi"&gt;48166&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;7196&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;22865&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;368&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3398&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41004&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;18139&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;519376&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;151&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5855&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;11710&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;519824&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;17036&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;22938&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;703&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3398&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41077&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;18139&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10533056&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;151&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5855&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;11710&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10533504&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;7340&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7218&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16423&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16446&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41146&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;33928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9448&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14016&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9896&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;7344&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7287&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16354&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16446&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41215&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;33928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;20568&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14016&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;21016&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们可以看到，在创建 long_str 对象之前，进程的内存是 7196KB，在创建 long_str 之后，使用内存上升到 17036KB, 这个是可以理解的。再看我们在 script 的第 13，14 行将 long_str 置空，并通过 ObjectSpace 强行启动一次回收，使用内存是 7340KB, 使用的内存变小了，基本回到了对象创建前的大小。&lt;code&gt;GC.stat&lt;/code&gt;中的 count 从 5 变成了 6，而且我们发现是 major_gc_count 从 2 变成了 3，也就是说启动的是一次 full 回收。并且，heap_live_slot 从 22938 变成了 7218，存活的对象的 slot 数目大幅减小，也就是说明很多对象已经被回收了。heap_free_slot 从原来的 703 变成了 16423，这个说明接下来如果进程还需要创建别的对象的话（需要的 slot 小于当前的 free_slot），可能就不需要操作系统分配新的内存而直接使用现在空闲的 free_slot 了。到底是不是上面的猜想呢，那我们再来实践下吧，将上面脚本的 18，19，20 行改成如下 ( 字符从 a 变成了 b）：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="n"&gt;long_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s2"&gt;" * 10_000_000
19 report
20 puts GC.stat 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看下结果如何：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ruby -v memory_profiler.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;p265&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2014&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="mi"&gt;48166&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;7180&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;22420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3845&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;18587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;518040&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;151&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5855&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;11710&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;518488&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;17028&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;22493&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;739&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3845&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;18587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10531688&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;151&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5855&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;11710&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10532136&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;7320&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7219&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16013&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16036&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41149&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;33930&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7009&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9880&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;17064&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7290&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;15942&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16036&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41220&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;33930&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10020560&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7009&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10021008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以发现使用的内存确实增加了，从 7320KB 变成了 17064KB，然而当前使用的 heap 个数（heap_used) 并没有变化，heap_live_slot 和 heap_free_slot 的变化也不大。Ruby 并没有将新的对象大量填充到 heap_free_slot，正因为先前所说的，heap 中的每个 RValue 结构体大小为 40bytes，并不能存放 long_str 那么大的字符串，当超出这个范围的时，Ruby 将其存放到了系统的 heap 去了，已经不由 RValue 结构来存储了。从上面的两次实验中也能看出，在每次启动 full 回收的时候，存储在系统 heap 中的大的对象被回收了，并且将这部分的内存归还给了操作系统。那么接下来就对比下，对于存放在 RValue 结构体中的变量，内存在垃圾回收后会不会将内存交还给系统呢？&lt;/p&gt;

&lt;p&gt;将上面的最初始的代码做如下修改，将名称改为 long_array, 并赋予一个很长的字符串数组：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#long_str = "a" * 10_000_000&lt;/span&gt;
&lt;span class="n"&gt;long_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10_000_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:to_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#long_str = nil&lt;/span&gt;
&lt;span class="n"&gt;long_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看下改变之后的内存使用状态：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ruby -v memory_profiler.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;p265&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2014&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="mi"&gt;48166&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;7172&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;22416&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;407&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3848&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;41002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;18586&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;517832&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;151&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;5855&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;11710&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;518280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16777216&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;511440&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24552&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;28695&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;4143&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10007226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;341&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24552&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10041080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;33854&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;29463768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;29936205&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;6497858&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7219894&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;49100440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;20132659&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;433404&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19660&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;28695&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19603&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7221&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8006375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8006398&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19603&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10041149&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10033928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;29337480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14014&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9880&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19737900&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Memory&lt;/span&gt; &lt;span class="mi"&gt;433408&lt;/span&gt;&lt;span class="no"&gt;KB&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_used&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19660&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;28695&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_increment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19603&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_live_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7290&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_free_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8006306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_final_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_swept_slot&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8006398&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_eden_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:heap_tomb_page_length&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19603&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_allocated_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10041218&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_freed_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10033928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;20552&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:malloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;29337480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:minor_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:major_gc_count&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remembered_shady_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_object_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14014&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_increase&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;21000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oldmalloc_limit&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;19737900&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以发现，分配大得数组之后使用内存飙升，从 7172KB 到 511440KB，GC 运行的次数也从 5 变成了 16，为系统分配了大量内存。在强行启动一次 full 回收之后，内存变为了 433404KB。和先前的例子对比下，发现内存在强行回收之后并没有回到之前的近似 7172KB 的内存大小，这是为什么呢？可以看到，long_array 是一个长度很大的数组，但是数组中的每个元素都很小，RValue 足够装下它。因此，虽然数组本身很大，但是这里的数组的元素还都是存在 RValue 结构中的，所以创建数组后 heap_used 的从 56 激增至 24552。但是在启动 full 回收后然而启动回收之后 heap_used 变成 19660，说明有一部分 heap 被回收了，仍然有很大一部分 heap 在使用。那又没有装对象呢？可以看到 heap_live_slot 由 10007226 个变成 7221，说明大部分对象都被释放掉了。很显然，Ruby 在释放对象这部分对象之后，并没有这部分对象占有的 heap 的内存全部交还给操作系统，即使你启动的是一次 full 的回收。这是 Ruby 的一种平衡，使得 Ruby 在下次分配对象的时候不需要时刻都向操作系统请求内存资源，而可以直接使用原来使用过的 free_slot。&lt;/p&gt;

&lt;p&gt;由此可见，不管是在你的程序中哪里，应尽量去避免创建这种极大的对象。因为一般情况下，Ruby 为了性能考虑，并不会经常启动 full 回收，也就是说有一部分对象并不会做 sweep 处理，依然残留在内存中，这会导致你的内存逐渐变大。即使对象被回收之后，内存也不会立马变得很小。结合我们前面的 Unicorn 的实例，我在极短的时间内，做了 1500 次图片的上传及处理，内存也在短时间内飙升，并在一定时间内并没有减小太多，这个道理是一致的。Ruby 在短时间内大量对象被创建的时候，是会申请较多的内存来处理的。即使在 free 掉相关对象后不将这部分内存归还给操作系统，所以你看到的现象是我为什么请求都停下来了，内存怎么还不降下去呢。当内存上升到一定程度，Ruby 会使用先前的 free_slot 来存放新的对象，这也就是为什么访问上升到一定程度之后，继续请求，内存使用增加依然较小。&lt;/p&gt;

&lt;p&gt;当然，除了上述情况之外，我们在写 Rails 和 Ruby 的时候还是要注意内存泄露的问题。在创建这些对象的时候，尽量不要把对象赋予给全局的变量或是类或 module 的属性，这会导致这些对象一直被 retained 而无法释放。此外，比较常用的跟 ActiveRecord 相关的操作，使用的好坏也对 Rails 内存有较大的影响。比如 model 的 all 和 find_each 方法的使用。在对数据库操作的时候，循环的使用是否合理等等，都对内存的使用会产生重大的影响。这里就不一一列举了。当然，应该还有许多我不知的相关方法来避免内存泄露和减少内存使用的问题，欢迎大家补充。&lt;/p&gt;

&lt;p&gt;此外，由于 Ruby 的不同版本，采用的 GC 实现方式也不同，特别是早前的 1.8, 1.9, 升级到 2.0 之后的版本，性能会有较大的提升。特别是 web app, 最开始都使用的是同一份代码，由于 Ruby 版本 GC 的实现机制不同，导致 Copy On Write 机制被利用程度也不同。在此就不详细展开了。详细可以参考&lt;a href="http://patshaughnessy.net/2012/3/23/why-you-should-be-excited-about-garbage-collection-in-ruby-2-0" rel="nofollow" target="_blank" title=""&gt;此文&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;总结下，以 Unicorn 服务器为例，可以通过减少 Unicorn 进程个数，杀死并重启新的 Unicorn Worker 来达到减少内存的使用。此外，通过对 Ruby 的 GC 机制的探讨，你可以尽量少创建大的对象及减少对全局变量的使用来控制内存。由于 Ruby 版本对于不同 GC 实现机制的不同，使得资源的使用效率上有着很大的差别，所以尽量把你的 Ruby 版本升级到 2.0 以上。&lt;/p&gt;

&lt;p&gt;下面的参考文献对文中提到的有一些概念都有比较深入的探讨，建议有时间可以阅读下。另外，附几个查看内存相关的 gem&lt;/p&gt;

&lt;p&gt;参考文献：
&lt;a href="http://patshaughnessy.net/2012/3/23/why-you-should-be-excited-about-garbage-collection-in-ruby-2-0" rel="nofollow" target="_blank"&gt;http://patshaughnessy.net/2012/3/23/why-you-should-be-excited-about-garbage-collection-in-ruby-2-0&lt;/a&gt;
&lt;a href="http://engineering.heroku.com/blogs/2015-02-04-incremental-gc/" rel="nofollow" target="_blank"&gt;http://engineering.heroku.com/blogs/2015-02-04-incremental-gc/&lt;/a&gt;
&lt;a href="http://samsaffron.com/archive/2013/11/22/demystifying-the-ruby-gc" rel="nofollow" target="_blank"&gt;http://samsaffron.com/archive/2013/11/22/demystifying-the-ruby-gc&lt;/a&gt;
&lt;a href="http://stackoverflow.com/questions/20385767/finding-the-cause-of-a-memory-leak-in-ruby" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/20385767/finding-the-cause-of-a-memory-leak-in-ruby&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;参考 gems：
&lt;a href="https://github.com/tmm1/rbtrace" rel="nofollow" target="_blank"&gt;https://github.com/tmm1/rbtrace&lt;/a&gt;  这个可以在你测试时查看 GC 等运行的状态，GC 多久跑一次等都可以监测到
&lt;a href="https://github.com/SamSaffron/memory_profiler" rel="nofollow" target="_blank"&gt;https://github.com/SamSaffron/memory_profiler&lt;/a&gt; 查看运行程序的内存状态 
&lt;a href="https://github.com/ko1/gc_tracer" rel="nofollow" target="_blank"&gt;https://github.com/ko1/gc_tracer&lt;/a&gt; Ruby GC 作者写的，虽然没有试用过^_^&lt;/p&gt;</description>
      <author>jackxu</author>
      <pubDate>Mon, 24 Aug 2015 11:33:34 +0800</pubDate>
      <link>https://ruby-china.org/topics/27057</link>
      <guid>https://ruby-china.org/topics/27057</guid>
    </item>
    <item>
      <title>Gemfile 详解</title>
      <description>&lt;p&gt;前几天读到的一篇博客，觉得内容很详实，就翻译了下给大家分享下。绝大部分为直译，极少数地方加了点自己的注释，若有不周到地方，还望大家指出。如果有排版方面的问题，也请指出。&lt;/p&gt;

&lt;p&gt;原文：&lt;a href="http://tosbourn.com/what-is-the-gemfile/" rel="nofollow" target="_blank" title=""&gt;http://tosbourn.com/what-is-the-gemfile/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作为 Ruby 开发者，我们一直在使用 Gemfile，并且大部分人知道一些关于 Gemfile 的基础知识。在这篇文章里，我想更加深入到 Gemfile 里面去看看通过 Gemfile 所能做的一切。&lt;/p&gt;
&lt;h4 id="什么是Gemfile"&gt;什么是 Gemfile&lt;/h4&gt;
&lt;p&gt;Gemfile 是我们创建的一个用于描述 gem 之间依赖的文件。gem 是一堆 Ruby 代码的集合，它能够为我们提供调用。你的 Gemfile 必须放在项目的根目录下面，这是 Bundler 的要求，对于任何的其他形式的包管理文件来说，这也是标准。这里值得注意的一点是 Gemfile 会被作为 Ruby 代码来执行。当在 Bundler 上下文环境中被执行的时能使我们访问一些方法，我们用这些方法来解释 gem 之间的 require 关系。&lt;/p&gt;
&lt;h4 id="创建Gemfile"&gt;创建 Gemfile&lt;/h4&gt;
&lt;p&gt;首先我们要做的就是告诉 Gemfile 到那里去找到这些 gems, 这就是 gem 的源。&lt;/p&gt;

&lt;p&gt;我们使用&lt;code&gt;#source&lt;/code&gt;方法来做这件事情&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"https://rubygems.org"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里并不推荐一个项目有多个源。对于 99% 的项目，你的 Gemfile 的源都会被要求设置为&lt;a href="https://rubygems.org" rel="nofollow" target="_blank" title=""&gt;https://rubygems.org&lt;/a&gt;，对于一个源，唯一的要求是它必须是一个合法的 Rubygems 的 repo。&lt;/p&gt;
&lt;h4 id="源的优先级"&gt;源的优先级&lt;/h4&gt;
&lt;p&gt;现在我们来探讨下关于 gem 源的优先级。
我们在 Gemfile 的顶部位置定义一个源的同时，我们也可以针对每个 gem 定义一个源。我们也能够为一个本地的 gem 定义一个路径或者是为 gem 定义一个 git 路径，比如说 GitHub 之类的（我们在后面点讲到这点）。
当 Bundler 尝试定位一个 gem 的时候，它会首先查看这个 gem 有没有显示的设置源，如果有，就先使用这个源。如果你在设置 gem 的时候有使用 source, path 或者 git 依赖的话，Bundler 将会先在这些地方找，然后再去其他地方寻找。如果没有被显示设置的话，Bundler 将会依照你 Gemfile 里面定义的源的顺序来找。如果一个 gem 能够在多个源里面被找到的话（虽然这是极为罕见的，因为你最好只定义一个源），你将会得到一个 warning 来提示你哪个源被使用了。&lt;/p&gt;

&lt;p&gt;你能够使#source 作为一个 block 来调用&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"https://my_awesome_source.com"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;my_other_gem&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="带验证的源"&gt;带验证的源&lt;/h4&gt;
&lt;p&gt;有些源需要你使用验证才能够被设定。Bundler 有一个设置选项使得你可以为每个源设置用户名和密码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="n"&gt;my_gem_source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;com&lt;/span&gt; &lt;span class="n"&gt;my_username&lt;/span&gt;&lt;span class="ss"&gt;:my_password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是任何希望通过 Bundler 来安装 gem 都必须要的因为它不会被放入版本管理里面。你也可以直接在 Gemfile 中设置你的验证信息，当然，这些验证信息也会被 commit 进你的版本管理工具。如下所示&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"https://username:password@my_gem_source.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你在源里面的设置，都会被你以 bundle config 的方式设置的东西所覆盖。&lt;/p&gt;
&lt;h4 id="设置Ruby信息"&gt;设置 Ruby 信息&lt;/h4&gt;
&lt;p&gt;如果你的应用程序需要使用一个特别的 Ruby 版本或是引擎，我们都能够在 Gemfile 里面进行设置。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="s2"&gt;"1.9.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:patchlevel&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"247"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:engine&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"jruby"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:engine_version&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"1.6.7"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当设定这个的时候，需要的唯一点信息就是 ruby 的版本（我们这里使用 1.9.3）
    *  :pathlevel 声明了 Ruby 的 patch level
    *  :engine 声明了使用的 Ruby 引擎
    *  :engine_version 声明了引擎的版本 (如果这个被设置了，engine 也需要被设置）&lt;/p&gt;
&lt;h4 id="设置Gems"&gt;设置 Gems&lt;/h4&gt;
&lt;p&gt;现在我们到了 Gemfile 的核心，设置你的 gems。最基本的语法如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里 my_gem 是 gem 的名字，gem 的名字是唯一要求的参数，此外还有几个可以选择的参数可以使用。&lt;/p&gt;
&lt;h4 id="设置Gem的版本"&gt;设置 Gem 的版本&lt;/h4&gt;
&lt;p&gt;对于一个 gem，你最常做的事情就是设置它的版本，如果你不设置版本的话，你也可以说任意的版本都可以。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里有 7 个操作符供你用来设置你的 gem&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* = Equal To "=1.0"
* != Not Equal To "!=1.0"
* &amp;gt; Greater Than "&amp;gt;1.0"
* &amp;lt; Less Than "&amp;lt;1.0"
* &amp;gt;= Greater Than or Equal To "&amp;gt;=1.0"
* &amp;lt;= Less Than or Equal To "&amp;lt;=1.0"
* ~&amp;gt; Pessimistically Greater Than or Equal To "~&amp;gt;1.0"
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="Pessimistically Greater Than or Equal To"&gt;Pessimistically Greater Than or Equal To&lt;/h4&gt;
&lt;p&gt;~&amp;gt; 操作能够让你使用这个 gem 的未来的某个安全的版本。如果你觉得使用一个大的版本更安全，你能够像下面这样声明。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 2.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这能够允许你安装任意的 2.x 版本的 gem，但是 3.x 版本是不被允许的。或许你对这么宽泛的版本感到不爽，你也可以声明一个更具体的版本，如下&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 2.5.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这能够让你使用 2.5.0 到 2.6.0 之间的版本。下面的例子能够让你更加理解~&amp;gt; 操作符&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0"&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt; 2.0"&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.5.0"&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 1.5.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt; 1.6.0"&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.5.5"&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 1.5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt; 1.6.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置gem被required"&gt;设置 gem 被 required&lt;/h4&gt;
&lt;p&gt;如果你使用 Rails 的话，这点小技巧可能被隐藏了，但是在你的 config/application.rb 文件里面你能看到这么一行代码。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Bundler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它的意思是 require 所有没有被放入 group（后面会讲到这个概念）里面的 gems 和所有放入和当前 rails 环境（RAILS_ENV, development, test, production) 同名的 group 里面的 gems。
默认方式下，如果你在 Gemfile 里面包含一个 gem，当 Bundler.require 被调用的时候会被包含进来。我们也能通过下面的设置让 gem 不被包含进来 (译者注释：这样你就只能安装这个 gem，在使用的时候必须在你的代码里手动的添加&lt;code&gt;require ‘my_gem’&lt;/code&gt;来调用 my_gem 里面的方法了。为什么需要这样呢，因为并不是所有的地方都需要使用这个 gem，比如你在 rake task 里面使用了 my_gem, 而其他地方没有使用，故你只需要在这个 gem require 到 task 里面，避免了所有的进程都把这个 gem 加载进去）&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;require: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当然你也可以指定哪些文件夹被 required 的，如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;require: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"my_gem/specific_module/my_class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这点在当你的 gem 有很多功能的，你必须每次手动 require 的时候非常有用。&lt;/p&gt;
&lt;h4 id="gem分组"&gt;gem 分组&lt;/h4&gt;
&lt;p&gt;正如我上面提到的一样，一个 gem 可以属于一个或多个 group，当它不属于任何 group 的时候，它被放入了&lt;code&gt;:default group&lt;/code&gt;。
有两种方法你可以对一个 gem 分组。第一种是对 group 属性进行赋值，如下所示：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;group: :development&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它的意思是，这个 gem 只在 development 环境下被 require。这也意味着当你在安装 gems 的时候，你可以指定某个 group 下面的 gems 不被安装，这样在一定程度上能加快 gem 的安装。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;without&lt;/span&gt; &lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的意思是安装除 development 和 test group 意外的所有 gems。
第二种 gem 分组的方法就是你可以将 gems 放入一个 block 里面，如下所示：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_other_gem"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这看上去更美观，并且你也可以设置多个 group。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_other_gem"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你想让某个 group 变成可选的形式，你也可以像下面这样，设置 optional: true&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;optional: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_other_gem"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当上面被设置时，为了安装 development group 下面的 gems，需要运行&lt;code&gt;bundle install —with development&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="设置gem的平台"&gt;设置 gem 的平台&lt;/h4&gt;
&lt;p&gt;如果某个 gem 只能在某个平台上使用，你也可以在 gemfile 里面设置。平台的原理和 group 很类似，但不同的是你不需要去通过—without 这样的 option 去指定，它会自动根据平台判断执行。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;platform: :jrubygem&lt;/span&gt; &lt;span class="s2"&gt;"my_other_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;platform: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:ruby&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:mri_18&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面是一个不同平台的 list。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* ruby – C Ruby (MRI) or Rubinius, but not Windows
* ruby_18 to ruby_22 – ruby &amp;amp; (version 1.8 .. version 2.2)
* mri – Same as ruby, but not Rubinius
* mri_18 to mri_22 – mri &amp;amp; (version 1.8 .. version 2.2)
* rbx – Same as ruby, but only Rubinius (not MRI)
* jruby – JRuby
* mswin – Windows
* mingw – Windows 32 bit mingw32 platform (aka RubyInstaller)
* mingw_18 to mingw_22 – mingw &amp;amp; (version 1.8 .. version 2.2)
* x64_mingw – Windows 64 bit mingw32 platform
* x64_mingw_20 to x64_mingw_22 – x64_mingw &amp;amp; (version 2.0 .. version 2.2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我发现平台真的非常有用，当一个开发团队在不同平台开发的时候。当你 team 的一个开发者使用的是 Windows 平台的时候，你可能需要不同版本的 gem 来支持。我经常使用下面的 block 语法来使用 platform 设定。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;platforms&lt;/span&gt; &lt;span class="ss"&gt;:jruby&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_other_gem"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置gem的源"&gt;设置 gem 的源&lt;/h4&gt;
&lt;p&gt;ok，现在我们来讲设置 gem 的源，如下所示：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;source: &lt;/span&gt;&lt;span class="s2"&gt;"https://my_awesome_gemsite.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果这个 my_gem 在 source 里面找不到的话，Bundler 也不会去 default 的源里面找，所以找不到的情况下这个 gem 就不会被安装。&lt;/p&gt;
&lt;h4 id="从git安装gem"&gt;从 git 安装 gem&lt;/h4&gt;
&lt;p&gt;你可以设置 gem 的安装源为一个 git repo，比如 GitHub, 这只需要你将 source 属性替换为 git。你可以设置这个 repo 的链接为 HTTP(S), SSH, GIT 等协议，但最好使用 HTTP(S) 和 SSH，因为其他的会使你可能成为 man-in-the-middle 攻击的受害者。如果你把 gem 放入到 repo 里面，你必须要在 repo 根目录文件夹下面有一个.gemspec  文件。这里面需要包含一个合法 gem 的声明。如果你没有提供这个文件，Bundler 会尝试创建一个，但是他不会被依赖。如果你尝试去 include 一个没有提供.gemspec 文件的 git repo 里面的 gem，你必须指定一个版本号。&lt;/p&gt;

&lt;p&gt;你可以为 gem 设置 branch，tag，ref，默认是使用 master branch。你也可以强制 Bundler 扩展 submodule，通过以下方式来设置：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;git: &lt;/span&gt;&lt;span class="s2"&gt;"ssh@githib.com/tosbourn/my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;branch: &lt;/span&gt;&lt;span class="n"&gt;test_branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;submodules: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你有多个 gem 来自同一个 git repo，你也可以通过下面 block 形式组织起来。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="s2"&gt;"git@github.com:tosbourn/my_gems.git"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_other_gem"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置Git作为source"&gt;设置 Git 作为 source&lt;/h4&gt;
&lt;p&gt;你可以设置一个 URL 来作为一个更广义的源，你可以通过调用#git_source 方法并将 name 作为参数传进去，以及一个接收一个参数的 block，并返回一个 string 作为 repo 的 URL。如下所示：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;git_source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:custom_git&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"https://my_secret_git_repos.com/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.git"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;custom_git: &lt;/span&gt;&lt;span class="s2"&gt;"tosbourn/test_repo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="BitBucket和Github的helper method"&gt;BitBucket 和 Github 的 helper method&lt;/h4&gt;
&lt;p&gt;因为 BitBucket 和 Github 都是比较流行的 git repo host，所以有两者的 helper method。在两者里面，Bundler 都默认 repo 是 public 的。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s2"&gt;"tosbourn/my_gem"&lt;/span&gt; 
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;bitbucket: &lt;/span&gt;&lt;span class="s2"&gt;"tosbourn/my_gem"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你也可以设置两者的 branch。当用户名和 repo 名字一致的时候，可以省略一个。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"rails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s2"&gt;"rails"&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"rails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;bitbucket: &lt;/span&gt;&lt;span class="s2"&gt;"rails"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：在 Bundler 2 出来之前，你不能使用:github 这个参数，目前它是使用 git://协议的，就是前面讲过的可能会受到 man-in-the-middle 攻击的。还有一个 helper :gist,  如果你 Github 上是以 gist 的形式存放的话就能够使用它。你可以只使用 gist ID 作为 path，也可以像:github, :bitbucket 那样传入:branch 参数。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:gist&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"5935162112"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;branch: &lt;/span&gt;&lt;span class="s2"&gt;"my_custom_branch"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="用path包含本地Gem"&gt;用 path 包含本地 Gem&lt;/h4&gt;
&lt;p&gt;你可以通过传入:path 参数来依赖你本地的 gems。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_gem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"../my_path/my_gem"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你传入一个相对路径的话（如上），这个路径是相对于你 Gemfile 的路径的。如果你想把某个文件夹下所有的 gems 都包含进去的话，你可以使用如下的 block。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path "../my_path/gems" do
  gem "my_gem"
  gem "my_other_gem"
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有一点值得注意的是，如果你使用的是 path 的话，Bundler 是不会编译 c extension 的。&lt;/p&gt;
&lt;h4 id="选择性的安装gems"&gt;选择性的安装 gems&lt;/h4&gt;
&lt;p&gt;有时候你想在某个前提条件被满足的情况下安装这个 gem，比如你系统里面是否有某个程序。下面这个方法能够接收一个 proc 或 lambda，下面的例子中我们将在你的系统是 mac 的时候安装这个 gem&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;install_if&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;RUBY_PLATFORM&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/darwin/&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"my_osx_gem"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="结束语"&gt;结束语&lt;/h4&gt;
&lt;p&gt;谢谢你的阅读并希望它能对你有所帮助，如果我有什么遗漏或你有什么问题的话请联系我~&lt;/p&gt;</description>
      <author>jackxu</author>
      <pubDate>Mon, 27 Jul 2015 09:05:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/26655</link>
      <guid>https://ruby-china.org/topics/26655</guid>
    </item>
  </channel>
</rss>
