为什么禁用GC时XML解析Ruby代码运行较慢?

为什么禁用GC时XML解析Ruby代码运行较慢?,ruby,performance,garbage-collection,Ruby,Performance,Garbage Collection,我有一段代码,使用libxmlrubygem解析500 MB的XML文件。令我惊讶的是,这段代码在禁用GC的情况下运行得更慢,这似乎违反了直觉。原因可能是什么?我有足够的可用内存,系统没有交换 require 'xml' #GC.disable @reader = XML::Reader.file('books.xml', :options => XML::Parser::Options::NOBLANKS) @reader.read @reader.read while @re

我有一段代码,使用
libxmlruby
gem解析500 MB的XML文件。令我惊讶的是,这段代码在禁用GC的情况下运行得更慢,这似乎违反了直觉。原因可能是什么?我有足够的可用内存,系统没有交换

require 'xml'

#GC.disable

@reader = XML::Reader.file('books.xml', :options => XML::Parser::Options::NOBLANKS)

@reader.read 
@reader.read

while @reader.name == 'book'
  book_id = @reader.get_attribute('id')
  @reader.read

  until @reader.name == 'book' && @reader.node_type == XML::Reader::TYPE_END_ELEMENT
    case @reader.name
    when 'author'
      author = @reader.read_string
    when 'title'
      title = @reader.read_string
    when 'genre'
      genre = @reader.read_string
    when 'price'
      price = @reader.read_string
    when 'publish_date'
      publish_date = @reader.read_string
    when 'description'
      description = @reader.read_string
    end
    @reader.next
  end

  @reader.read      

end
@reader.close
以下是我得到的结果:

ruby     gc on   gc off
2.2.0    16.93s  18.81s
2.1.5    16.22s  18.58s
2.0.0    17.63s  17.99s
为什么要禁用垃圾收集器?我在书中读到Ruby的速度很慢,主要是因为程序员不考虑内存消耗,这使得垃圾收集器占用了大量的执行时间。因此,只要系统不进行交换,关闭GC就会立即加快速度(当然是以内存使用为代价的)

我想看看我的XML解析模块是否可以改进,所以我开始通过禁用GC来尝试它,这就导致了这个问题。我期望在禁用GC的情况下有一个显著的加速,但是我得到了相反的结果。我知道差别不大,但这对我来说还是很奇怪

libxml-ruby
gem在引擎盖下使用本机C
libxml
实现——这可能是原因吗

我使用的文件是从一些Microsoft文档下载的手动乘法
books.xml
sample:

<catalog>
 <book id="bk101">
  <author>John Doe</author>
  <title>XML for dummies</title>
  <genre>Computer</genre>
  <price>44.95</price>
  <publish_date>2000-10-01</publish_date>
  <description>Some description</description>
 </book>
 ....
</catalog>

无名氏
傻瓜的XML
电脑类
44.95
2000-10-01
一些描述
....
我的设置:OS X Yosemite,Intel Core i5 2.6 GHz,16GB内存


谢谢您的建议。

您忘记了操作系统-您在MRI进程中禁用了GC,但无法控制linux/unix内核及其如何为MRI应用程序分配内存

事实上,我相信禁用GC会大大削弱应用程序的行为,使程序可能需要不断地从内核请求更多的RAM。这可能会涉及内核中的某种形式的开销,因为它会将交换或内存分配给您

您的源数据是一个500 mb的xml文件,您正在逐节点将其读取到MRI程序的内存占用中。你的核磁共振成像过程在完成处理时可能会消耗数GB的数据;在每次迭代之后,主读取块中的值都不会被丢弃——它们只是挂在内存中,只有在应用程序退出并将内存返回到操作系统时才会被最终清除

GC已到位以管理这一点;它旨在防止应用程序从内核请求额外内存,除非它绝对需要它,并允许应用程序在合理分配给它的内存中“足够好”地运行


因此,我并不真的感到惊讶,你看到GC被禁用会减速。在基准测试过程中,你的盒子的平均负载和交换使用率是最能说明问题的。

@engineersmnky如果他问的是如何让它更快,那么它就属于这里,而不是代码审查。如果他需要所有方面的帮助,应该去那里。@engineersmnky“原因可能是什么?我有足够的可用内存,并且系统没有交换。”@engineersmnky请参阅下面的部分,其中说“我需要有关代码任何或所有方面的反馈吗?”。OP不需要这种反馈。@engineersmnky与代码审查迁移建议中经常提到的相反,特定的代码改进绝对是关于堆栈溢出的主题。在任何情况下,正如我所能说的,OP不是在要求性能调整,而是在问一个特定的问题,为什么垃圾收集器在这种情况下表现出与预期相反的行为。感谢您对OS分配开销的建议。考虑到这一点,我会做一些额外的基准测试。想必你是对的。我可以看到,这个过程不断地以小增量分配越来越多的内存。为了证明你的观点,我寻找了一种在开始时预先分配大量内存的方法(比如Java中的
-Xmx
开关),这样在执行过程中就不必花费任何时间。但显然这在Ruby中是不可能的。