是否有必要在Ruby中关闭StringIO?
我们需要在使用
Ruby之后关闭StringIO对象,以便释放资源,就像我们用真正的IO对象一样?
obj = StringIO.new "some string" #... obj.close # <--- Do we need to close it? 精炼我的问题 关闭File对象是必要的,因为它将关闭文件描述符.打开的文件的数量在操作系统中受到限制,这就是为什么需要关闭文件.但是,如果我理解正确,StringIO是内存中的抽象.我们需要关闭吗? 解决方法
> StringIO#close不释放任何资源或放弃对累积字符串的引用.因此调用它对资源使用没有影响.
>只有StringIO#finalize,在垃圾收集期间调用,释放对累积字符串的引用,以便它可以被释放(前提是调用者不保留对它的引用). > StringIO.open,它简单地创建一个StringIO实例,它不返回时保留对该实例的引用;因此,StringIO对累积字符串的引用可以被释放(前提是调用者不保留对其的引用). >实际上,使用StringIO时很少需要担心内存泄漏.一旦你完成他们,只要不要参考StringIO,一切都会好起来的. 潜入源头 StringIO实例使用的唯一资源是它正在积累的字符串.你可以看到在stringio.c(MRI 1.9.3);这里我们看到一个持有StringIO状态的结构: static struct StringIO *struct StringIO { VALUE string; long pos; long lineno; int flags; int count; }; 当一个StringIO实例被完成(即垃圾回收)时,它引用该字符串将被丢弃,以便如果没有其他引用,则可能会收集该字符串的垃圾回收.这是finalize方法,它也被StringIO#open(& block)调用以关闭实例. static VALUE strio_finalize(VALUE self) { struct StringIO *ptr = StringIO(self); ptr->string = Qnil; ptr->flags &= ~FMODE_READWRITE; return self; } 只有当对象被垃圾回收时才调用finalize方法. StringIO没有其他方法可以释放字符串引用. StringIO#close只是设置一个标志.它不会释放对累积字符串的引用或以任何其他方式影响资源使用: static VALUE strio_close(VALUE self) { struct StringIO *ptr = StringIO(self); if (CLOSED(ptr)) { rb_raise(rb_eIOError,"closed stream"); } ptr->flags &= ~FMODE_READWRITE; return Qnil; } 最后,当您调用StringIO#string时,您将获得与StringIO实例已经累积的完全相同的字符串的引用: static VALUE strio_get_string(VALUE self) { return StringIO(self)->string; } 使用StringIO时如何泄漏内存 所有这一切意味着只有一种方法可以使StringIO实例引起资源泄漏:您不能关闭StringIO对象,并且您必须将其保留的时间长于在调用StringIO#string时保留字符串的长度.例如,假设一个具有StringIO对象作为实例变量的类: class Leaker def initialize @sio = StringIO.new @sio.puts "Here's a large file:" @sio.puts @sio.write File.read('/path/to/a/very/big/file') end def result @sio.string end end 想象一下,这个类的用户得到结果,简单地使用它,然后丢弃它,并保留对Leaker实例的引用.您可以看到,Leaker实例通过未关闭的StringIO实例保留对结果的引用.这可能是一个问题,如果文件是非常大的,或者有很多现存的实例的Leaker.这个简单(和故意病理)的例子可以通过简单地不把StringIO保持为一个实例变量来解决.当你可以(而且你几乎总是可以)时,最好简单地扔掉StringIO对象,而不是明确地关闭它: class NotALeaker attr_reader :result def initialize sio = StringIO.new sio.puts "Here's a large file:" sio.puts sio.write File.read('/path/to/a/very/big/file') @result = sio.string end end 添加到所有这些,这些泄漏只有当字符串很大或StringIO实例很多,StringIO实例是长寿命的时候才是重要的,你可以看到,显然关闭StringIO很少需要. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |