是否有必要在 ruby​​ 中关闭 StringIO? [英] Is it necessary to close StringIO in ruby?

查看:43
本文介绍了是否有必要在 ruby​​ 中关闭 StringIO?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们是否需要在 Ruby 中使用后关闭 StringIO 对象以释放资源,就像我们处理真正的 IO 对象一样?

Do we need to close StringIO objects after usage in Ruby in order to free resources, like we do with the real IO objects?

obj = StringIO.new "some string"
#...
obj.close # <--- Do we need to close it?

完善我的问题

关闭文件对象是必要的,因为它将关闭文件描述符.操作系统中打开文件的数量是有限的,这就是为什么有必要关闭文件.但是,如果我理解正确的话,StringIO 是内存中的抽象.我们需要关闭它吗?

Closing File object is necessary because it will close the file descriptor. The number of opened files is limited in the OS, and that's why it is necessary to close File. But, if I understand correctly, StringIO is an abstraction in memory. Do we need to close it?

推荐答案

  • StringIO#close 不会释放任何资源或删除其对累积字符串的引用.因此调用它对资源使用没有影响.

    • StringIO#close does not free any resources or drop its reference to the accumulated string. Therefore calling it has no effect upon resource usage.

      只有在垃圾回收期间调用的 StringIO#finalize 释放对累积字符串的引用,以便可以释放它(前提是调用者不保留自己对它的引用).

      Only StringIO#finalize, called during garbage collection, frees the reference to the accumulated string so that it can be freed (provided the caller does not retain its own reference to it).

      StringIO.open,它简要地创建了一个 StringIO 实例,在它返回后不保留对该实例的引用;因此可以释放 StringIO 对累积字符串的引用(前提是调用者不保留自己对它的引用).

      StringIO.open, which briefly creates a StringIO instances, does not keep a reference to that instance after it returns; therefore that StringIO's reference to the accumulated string can be freed (provided the caller does not retain its own reference to it).

      实际上,使用 StringIO 时很少需要担心内存泄漏.一旦你完成了对 StringIO 的引用,就不要再坚持下去了,一切都会好起来的.

      In practical terms, there is seldom a need to worry about a memory leak when using StringIO. Just don't hang on to references to StringIO once you're done with them and all will be well.

      深入源头

      StringIO 实例使用的唯一资源是它正在累积的字符串.您可以在 stringio.c (MRI 1.9.3) 中看到;在这里我们看到保存 StringIO 状态的结构:

      The only resource used by a StringIO instance is the string it is accumulating. You can see that in stringio.c (MRI 1.9.3); here we see the structure that holds a StringIO's state:

      static struct StringIO *struct StringIO {
          VALUE string;
          long pos;
          long lineno;
          int flags;
          int count;
      };
      

      当一个 StringIO 实例完成(即垃圾回收)时,它对字符串的引用将被删除,以便该字符串可能被垃圾回收如果没有其他引用.这是 finalize 方法,它也被 StringIO#open(&block) 调用以关闭实例.

      When a StringIO instance is finalized (that is, garbage collected), its reference to the string is dropped so that the string may be garbage collected if there are no other references to it. Here's the finalize method, which is also called by StringIO#open(&block) in order to close the instance.

      static VALUE
      strio_finalize(VALUE self)
      {
          struct StringIO *ptr = StringIO(self);
          ptr->string = Qnil;
          ptr->flags &= ~FMODE_READWRITE;
          return self;
      }
      

      finalize 方法只在对象被垃圾回收时调用.StringIO 没有其他方法可以释放字符串引用.

      The finalize method is called only when the object is garbage collected. There is no other method of StringIO which frees the string reference.

      StringIO#close 只是设置一个标志.它不会释放对累积字符串的引用或以任何其他方式影响资源使用:

      StringIO#close just sets a flag. It does not free the reference to the accumulated string or in any other way affect resource usage:

      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 实例一直在累积的完全相同字符串的引用:

      And lastly, when you call StringIO#string, you get a reference to the exact same string that the StringIO instance has been accumulating:

      static VALUE
      strio_get_string(VALUE self)
      {   
          return StringIO(self)->string;
      }
      

      <小时>

      使用StringIO时如何泄漏内存

      所有这一切意味着 StringIO 实例导致资源泄漏的方法只有一种:您不能关闭 StringIO 对象,并且您必须将其保留的时间长于调用 StringIO#string.例如,想象一个类有一个 StringIO 对象作为实例变量:

      All of this means that there is only one way for a StringIO instance to cause a resource leak: You must not close the StringIO object, and you must keep it around longer than you keep the string you got when you called StringIO#string. For example, imagine a class having a StringIO object as an instance variable:

      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 对象,而不是费力地将其显式关闭:

      Imagine that the user of this class gets the result, uses it briefly, and then discards it, and yet keeps a reference to the instance of Leaker. You can see that the Leaker instance retains a reference to the result via the un-closed StringIO instance. This could be a problem if the file is very large, or if there are many extant instance of Leaker. This simple (and deliberately pathological) example can be fixed by simply not keeping the StringIO as an instance variable. When you can (and you almost always can), it's better to simply throw away the StringIO object than to go through the bother of closing it explicitly:

      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 的情况很少,如果曾经,需要.

      Add to all of this that these leaks only matter when the strings are large or the StringIO instances numerous and the StringIO instance is long lived, and you can see that explicitly closing StringIO is seldom, if ever, needed.

      这篇关于是否有必要在 ruby​​ 中关闭 StringIO?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆