佐々木です。
ありがとうございます。

下記スクリプトを実行すると1.8(ちょっと古いのですが)では251回目で
Errno::EMFILEとなってしまいました。
例外オブジェクトが持つioがcloseされないようです。

しかし、1.9では2000回まで行きました。

======================
require "pp"
require "open-uri"

p [RUBY_VERSION,RUBY_PATCHLEVEL,RUBY_RELEASE_DATE,RUBY_PLATFORM]
pid = Process.pid
puts "pid=#{pid}"

url = "http://ssktkr.com/asdf"

puts "before -----------------------------"
puts `lsof -p #{pid}`
2000.times do |n|
  puts "n=#{n}"
  begin
    open(url) do |f|
      p f
    end
  rescue OpenURI::HTTPError => e
    p e
    pp e.backtrace
    #e.io.close
  end
end
GC.start
puts "after -----------------------------"
puts `lsof -p #{pid}`
======================

ruby open_uri_bug.rb
["1.8.6", 114, "2008-03-03", "i686-darwin8.11.1"]
pid=29011
before -----------------------------
COMMAND   PID   USER   FD     TYPE    DEVICE SIZE/OFF     NODE NAME
ruby    29011 takeru  cwd      DIR      14,2     4998  1356361 /Users/takeru/tmp
ruby    29011 takeru  txt      REG      14,2    13412   550135
/opt/local/bin/ruby
ruby    29011 takeru  txt      REG      14,2    23860   559917
/opt/local/lib/ruby/1.8/i686-darwin8.11.1/stringio.bundle
ruby    29011 takeru  txt      REG      14,2   783224   552430
/opt/local/lib/libruby.1.8.6.dylib
ruby    29011 takeru  txt      REG      14,2  1688500  1538264 /usr/lib/dyld
ruby    29011 takeru  txt      REG      14,2  8008576  7501385
/usr/lib/libSystem.B.dylib
ruby    29011 takeru  txt      REG      14,2  1580212  7501394
/usr/lib/libobjc.A.dylib
ruby    29011 takeru  txt      REG      14,2  3559472  7501739
/usr/lib/libstdc++.6.0.4.dylib
ruby    29011 takeru  txt      REG      14,2   251320  7501746
/usr/lib/libgcc_s.1.dylib
ruby    29011 takeru  txt      REG      14,2   212160  7501474
/usr/lib/libauto.dylib
ruby    29011 takeru    0u     CHR      4,20  0t49144 61411076 /dev/ttyq4
ruby    29011 takeru    1u     CHR      4,20  0t49144 61411076 /dev/ttyq4
ruby    29011 takeru    2u     CHR      4,20  0t49144 61411076 /dev/ttyq4
ruby    29011 takeru    3     PIPE 0x400c248    16384
ruby    29011 takeru   11r  PSXSHM               4096
apple.shm.notification_center
n=0
#<OpenURI::HTTPError: 404 Not Found>
["/opt/local/lib/ruby/1.8/open-uri.rb:278:in `open_http'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:617:in `buffer_open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:164:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `catch'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:132:in `open_uri'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:519:in `open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:30:in `open'",
 "open_uri_bug.rb:15",
 "open_uri_bug.rb:12:in `times'",
 "open_uri_bug.rb:12"]
n=1
#<OpenURI::HTTPError: 404 Not Found>
["/opt/local/lib/ruby/1.8/open-uri.rb:278:in `open_http'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:617:in `buffer_open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:164:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `catch'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:132:in `open_uri'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:519:in `open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:30:in `open'",
 "open_uri_bug.rb:15",
 "open_uri_bug.rb:12:in `times'",
 "open_uri_bug.rb:12"]

(snip)

n=249
#<OpenURI::HTTPError: 404 Not Found>
["/opt/local/lib/ruby/1.8/open-uri.rb:278:in `open_http'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:617:in `buffer_open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:164:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `catch'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:132:in `open_uri'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:519:in `open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:30:in `open'",
 "open_uri_bug.rb:15",
 "open_uri_bug.rb:12:in `times'",
 "open_uri_bug.rb:12"]
n=250
#<OpenURI::HTTPError: 404 Not Found>
["/opt/local/lib/ruby/1.8/open-uri.rb:278:in `open_http'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:617:in `buffer_open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:164:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `catch'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:162:in `open_loop'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:132:in `open_uri'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:519:in `open'",
 "/opt/local/lib/ruby/1.8/open-uri.rb:30:in `open'",
 "open_uri_bug.rb:15",
 "open_uri_bug.rb:12:in `times'",
 "open_uri_bug.rb:12"]
n=251
/opt/local/lib/ruby/1.8/tempfile.rb:55:in `initialize': Too many open
files - /tmp/open-uri.29011.251 (Errno::EMFILE)
        from /opt/local/lib/ruby/1.8/tempfile.rb:55:in `open'
        from /opt/local/lib/ruby/1.8/tempfile.rb:55:in `initialize'
        from /opt/local/lib/ruby/1.8/open-uri.rb:303:in `new'
        from /opt/local/lib/ruby/1.8/open-uri.rb:303:in `<<'
        from /opt/local/lib/ruby/1.8/open-uri.rb:259:in `open_http'
        from /opt/local/lib/ruby/1.8/net/protocol.rb:381:in `call_block'
        from /opt/local/lib/ruby/1.8/net/protocol.rb:372:in `<<'
        from /opt/local/lib/ruby/1.8/net/protocol.rb:84:in `read'
         ... 15 levels...
        from /opt/local/lib/ruby/1.8/open-uri.rb:30:in `open'
        from open_uri_bug.rb:15
        from open_uri_bug.rb:12:in `times'
        from open_uri_bug.rb:12
tkrmb:tmp%









2009年9月11日7:46 Yukihiro Matsumoto <matz / ruby-lang.org>:
> まつもと ゆきひろです
>
> In message "Re: [ruby-dev:39302] Re: [Bug #2067] bodyが大きいエラーページをopen-uriで取得するとfdがリークしている"
>    on Fri, 11 Sep 2009 01:34:01 +0900, takeru sasaki <sasaki.takeru / gmail.com> writes:
>
> |GC.start
> |の様に書けば確実にcloseされるのなら問題ないですが、そうでもないようです。
>
> RubyのGCは保守的なのですべて回収されることは保証できません。
>
> |GCでは未使用のメモリを回収してくれるだけで未使用のfdを回収してくれることは
> |ないのですよね。
> |メモリに余裕がある状態だとfdをつかんだ例外オブジェクトも回収されず、
> |fdも開きっぱなしになるのではないかとおもいます。
> |(再現スクリプトでは1.9では開きっぱなしのfdの数が少ないです。GCが効いている?)
>
> GCは参照されていないオブジェクトを回収します。そのオブジェク
> トがfdを持てば、それは自動的にcloseします。
>
> |この問題に気がついたのは、「EMFILE too many open files」になったせいでした。
> |例外オブジェクトへの参照は確実に無いはずで(メソッドからreturnしている)
> |gcされるより前にtoo many open filesにぶつかったのでした。
>
> RubyはEMFILEが発生すると自動的にGCを起動します。それでもなお
> EMFILEが出ると言うことは、また別の問題を示唆しますね。
>
>