[#31143] m {|(*,(*)),|} — Tanaka Akira <akr@...>
m {|(*,(*)),|} で SEGV します。
[#31164] ruby_set_current_source remains in intern.h — Masahiro Sakai (酒井政裕) <masahiro.sakai@...>
酒井です。
[#31166] is_ruby_native_thread() — Masahiro Sakai (酒井政裕) <masahiro.sakai@...>
酒井です。
なかだです。
永井@知能.九工大です.
なかだです。
永井@知能.九工大です.
ささだです。
[#31168] 構造体オブジェクトのcloneメソッド呼び出しでメモリリーク発生 — m-ohkubo@... (Mitsuhiko OHKUBO)
大久保といいます。はじめまして。
なかだです。
大久保です。よろしくお願いします。
[#31190] 0x3fffffffffffffff.succ — Tanaka Akira <akr@...>
LP64 環境で 0x3fffffffffffffff.succ が -4611686018427387904
[#31214] Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead — Kazuhiro NISHIYAMA <zn@...>
西山和広です。
[#31222] trunk: バグを指摘している警告 — pegacorn <subscriber.jp@...>
trunk で -Wall を付けてコンパイルしてみると、バグを指摘している警告が
From: pegacorn <subscriber.jp@gmail.com>
[#31242] p(65536**(1<<29)) stalls — "Yusuke ENDOH" <mame@...>
遠藤と申します。
[#31244] shift — Tanaka Akira <akr@...>
-O0 で、以下のようにすると SEGV になります。
なかだです。
In article <200707180743.l6I7hXic031558@sharui.nakada.kanuma.tochigi.jp>,
[#31285] p()#=>[] — eklerni <eklerni@...>
松尾といいます。
[#31292] ParseDate.parsedate("Tuesday, July 6th, 2007, 18:35:20 UTC") — Tanaka Akira <akr@...>
ParseDate のマニュアルにある以下の例を動かすと、示された結果
[#31298] retryの使い方 — eklerni <eklerni@...>
松尾といいます。
ささだです。
松尾です、返信ありがとうございます。
Yuguiといいます。
松尾といいます。
In article <46A909DD.1070405@for.mail-box.ne.jp>,
Tanaka Akira さんは書きました:
In article <46A92530.80507@for.mail-box.ne.jp>,
Tanaka Akira さんは書きました:
In article <46AD7A16.8080509@for.mail-box.ne.jp>,
松尾です。
ささだです。
From:eklerni
まつもと ゆきひろです
In article <E1ILDTi-0005T6-Be@x31>,
まつもと ゆきひろです
In article <E1ILKn6-0003Nv-0f@x31>,
まつもと ゆきひろです
In article <E1ILVN9-0006xJ-7I@x31>,
In article <E1ILq4x-0002Bs-Lg@x31>,
まつもと ゆきひろです
In article <E1ILweZ-00008I-Tu@x31>,
まつもと ゆきひろです
In article <E1ILyGa-0000ug-Qd@x31>,
まつもと ゆきひろです
In article <E1IM1W9-0001uC-Bz@x31>,
まつもと ゆきひろです
[ruby-dev:31319] DelegatorおよびWeakRefのメモリ使用量
野口と申します。
長文失礼致します。
WeakRefオブジェクトを大量に生成するプログラムで
NoMemoryErrorが発生するようになったので、調べてみたところ
delegate.rbにて委譲するメソッドを特異メソッドとして定義する際に、
同じ正規表現オブジェクトを大量に生成していることに気づきました。
特に理由がないのであれば、定数に置き換えるなどして無駄なオブジェクト
生成を避けた方がよいと思うのですが、いかがでしょうか。
--- delegate.rb.orig Tue Feb 13 08:01:19 2007
+++ delegate.rb Wed Aug 1 04:14:03 2007
@@ -116,6 +116,7 @@
#
class Delegator
+ IgnoreBacktracePat = /^\(eval\):|:in `__getobj__'$/
#
# Pass in the _obj_ to delegate method calls to. All methods supported by
# _obj_ will be delegated to.
@@ -138,8 +139,7 @@
begin
__getobj__.__send__(:#{method}, *args, &block)
rescue Exception
- $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
- $@.delete_if{|s| /^\\(eval\\):/ =~ s}
+ $@.delete_if{|s| ::Delegator::IgnoreBacktracePat =~ s}
Kernel::raise
end
end
参考までにベンチマークを取ってみました。
実行時間とプロセスのサイズを測っています。
コード:
require 'weakref'
require 'benchmark'
n = 1000
open("weakref_bench.log", "w"){|f|
Benchmark.bm do |x|
GC.start
refs = Array.new(n)
x.report("#{n} times with WeakRef") do
n.times do |i|
if i % 200 == 0
GC.start
f.puts("%07d: %s" % [i, open("|ps
awxl").readlines.grep(/ruby\s+weakref_bench.rb/)[0].chomp])
end
obj = {}
refs << WeakRef.new(obj)
obj = nil
end
end
end
}
ここまで
変更前
結果:
$ruby -v
ruby 1.8.6 (2007-06-07 patchlevel 36) [i386-freebsd6.1]
$ruby weakref_bench.rb
user system total real
1000 times with WeakRef 21.812500 1.890625 23.703125 ( 27.346026)
weakref_bench.log:
0000000: 1001 29171 12538 2 -8 0 2676 2100 piperd S+ p1
0:00.03 ruby weakref_bench.rb
0000200: 1001 29171 12538 44 -8 0 68388 63316 piperd S+ p1
0:03.51 ruby weakref_bench.rb
0000400: 1001 29171 12538 126 -8 0 127672 118144 piperd S+ p1
0:07.74 ruby weakref_bench.rb
0000600: 1001 29171 12538 128 112 0 165688 151676 - R+ p1
0:12.53 ruby weakref_bench.rb
0000800: 1001 29171 12538 107 -8 0 242488 224020 piperd S+ p1
0:18.11 ruby weakref_bench.rb
正規表現を定数に変更後(grepの引数と書き出すファイル名を変更しています):
結果:
$ruby weakref2_bench.rb
user system total real
1000 times with WeakRef 12.460938 0.679688 13.140625 ( 13.334997)
weakref2_bench.log:
0000000: 1001 29177 12538 11 -8 0 2676 2100 piperd S+ p1
0:00.03 ruby weakref2_bench.rb
0000200: 1001 29177 12538 162 -8 0 20644 20104 piperd S+ p1
0:02.35 ruby weakref2_bench.rb
0000400: 1001 29177 12538 154 -8 0 35808 35288 piperd S+ p1
0:04.96 ruby weakref2_bench.rb
0000600: 1001 29177 12538 253 -8 0 57356 56852 piperd S+ p1
0:07.62 ruby weakref2_bench.rb
0000800: 1001 29177 12538 251 -8 0 97232 96768 piperd S+ p1
0:10.54 ruby weakref2_bench.rb
見たところ、メモリ消費量も実行時間も半分近くにはなっているようです。
もっとも、これでもオブジェクトごとに特異メソッドを定義しているのですが
問題が発生したプログラムでは、オブジェクトごとに特異メソッドを定義する必要は
なかったので、Delegatorに対するDelegateClassのように、WeakRefに対する
WeakRefClassを、weakref.rbを参考に定義してみました。
こちらを使うとクラス一つの定義で済むので大幅にパフォーマンスが改善するようです。
コード:
require 'weakref_class'
require 'benchmark'
class Dummy < WeakRefClass( Hash )
def initialize
super({})
end
end
n = 1000
open("weakref_class_bench.log", "w"){|f|
Benchmark.bm do |x|
GC.start
refs = Array.new(n)
x.report("#{n} times with WeakRefClass") do
n.times do |i|
if i % 200 == 0
f.puts("%07d: %s" % [i, open("|ps
awxl").readlines.grep(/ruby\s+weakref_class_bench.rb/)[0].chomp])
GC.start
end
obj = {}
refs << Dummy.new
obj = nil
end
end
end
}
ここまで
$ruby weakref_class_bench.rb
user system total real
1000 times with WeakRefClass 0.070312 0.007812 0.078125 ( 0.134467)
0000000: 1001 29189 12538 5 -8 0 3088 2512 piperd S+ p1
0:00.04 ruby weakref_class_bench.rb
0000200: 1001 29189 12538 13 -8 0 3088 2536 piperd S+ p1
0:00.05 ruby weakref_class_bench.rb
0000400: 1001 29189 12538 30 -8 0 3088 2536 piperd S+ p1
0:00.06 ruby weakref_class_bench.rb
0000600: 1001 29189 12538 63 -8 0 3088 2536 piperd S+ p1
0:00.08 ruby weakref_class_bench.rb
0000800: 1001 29189 12538 130 -8 0 3088 2536 piperd S+ p1
0:00.10 ruby weakref_class_bench.rb
weakref_class.rb:
require 'weakref'
module WeakRefMixIn
RefError = WeakRef::RefError
@@id_map = {} # obj -> [ref,...]
@@id_rev_map = {} # ref -> obj
@@final = lambda{|id|
__old_status = Thread.critical
Thread.critical = true
begin
rids = @@id_map[id]
if rids
for rid in rids
@@id_rev_map.delete(rid)
end
@@id_map.delete(id)
end
rid = @@id_rev_map[id]
if rid
@@id_rev_map.delete(id)
@@id_map[rid].delete(id)
@@id_map.delete(rid) if @@id_map[rid].empty?
end
ensure
Thread.critical = __old_status
end
}
def initialize(orig)
__setobj__(orig)
end
def __setobj__(obj)
@__id = obj.__id__
__old_status = Thread.critical
begin
Thread.critical = true
unless @@id_rev_map.key?(self)
ObjectSpace.define_finalizer obj, @@final
ObjectSpace.define_finalizer self, @@final
end
@@id_map[@__id] = [] unless @@id_map[@__id]
ensure
Thread.critical = __old_status
end
@@id_map[@__id].push self.__id__
@@id_rev_map[self.__id__] = @__id
end
def method_missing(m, *args)
target = self.__getobj__
unless target.respond_to?(m)
super(m, *args)
end
target.__send__(m, *args)
end
def respond_to?(m)
return true if super
return self.__getobj__.respond_to?(m)
end
def __getobj__
unless @@id_rev_map[self.__id__] == @__id
raise RefError, "Illegal Reference - probably recycled", caller(2)
end
begin
ObjectSpace._id2ref(@__id)
rescue RangeError
raise RefError, "Illegal Reference - probably recycled", caller(2)
end
end
# Returns true if the referenced object still exists, and false if it has
# been garbage collected.
def weakref_alive?
@@id_rev_map[self.__id__] == @__id
end
# Clone support for the object returned by \_\_getobj\_\_.
def clone
super
__setobj__(__getobj__.clone)
end
# Duplication support for the object returned by \_\_getobj\_\_.
def dup(obj)
super
__setobj__(__getobj__.dup)
end
end
def WeakRefClass(superclass)
klass = Class.new
klass.module_eval {
include WeakRefMixIn
}
methods = superclass.public_instance_methods(true)
methods -= ::Kernel.public_instance_methods(false)
methods -= %w[to_s to_a inspect == =~ ===]
methods -= WeakRefMixIn.public_instance_methods(false)
methods -= WeakRefMixIn.private_instance_methods(false)
methods -= WeakRefMixIn.protected_instance_methods(false)
for method in methods
begin
klass.module_eval <<-EOS
def #{method}(*args, &block)
begin
__getobj__.__send__(:#{method}, *args, &block)
rescue
$@[0, 2] = nil
raise
end
end
EOS
rescue SyntaxError
raise NameError, "invalid identifier %s" % method, caller(3)
end
end
return klass
end
ここまで
---
GO Noguchi<gonoguti@yahoo.co.jp>