【问题标题】:Object address in RubyRuby 中的对象地址
【发布时间】:2010-10-24 21:28:07
【问题描述】:

短版: 类的默认inspect 方法显示对象的地址。* 如何在我自己的自定义inspect 方法中做到这一点?

*(说清楚,我想要你通常从inspect 得到的 8 位十六进制数。我不关心实际的内存地址。我只是称它为内存地址,因为它 看起来像一个。我知道 Ruby 是内存安全的。)

长版:我有两个课程,ThingThingListThingListArray 的子类,专门设计用于保存事物。由于事物的性质以及它们在我的程序中的使用方式,事物有一个实例变量@container,它指向包含ThingThingList

两个事物有可能拥有完全相同的数据。因此,当我调试应用程序时,我能够可靠地区分两个事物的唯一方法是使用inspect,它会显示它们的地址。但是,当我 inspectThing 时,我会得到一页一页的输出,因为 inspect 将递归检查 @container,导致列表中的每个事物也被检查!

我只需要输出的第一部分。如何在 Thing 上编写一个自定义的 inspect 方法来显示这个?

#<Thing:0xb7727704>

编辑:我刚刚意识到默认的to_s 就是这样做的。我之前没有注意到这一点,因为我有一个自定义的to_s,它提供了关于对象的可读详细信息。

假设我不能使用to_s,我必须编写一个自定义的inspect

【问题讨论】:

    标签: ruby debugging memory-address inspect


    【解决方案1】:

    您可以使用 object_id 获取地址并将其乘以 2* 并使用 sprintf(又名 %)以十六进制显示:

    "#<Thing:0x%08x>" % (object_id * 2)
    

    当然,只要你只需要唯一的号码而不关心它是实际地址,你可以省略* 2

    * 由于你不需要理解的原因(意思是:我不理解它们),object_id 返回一半的对象的内存地址,所以你需要乘以 2获取实际地址。

    【讨论】:

    • 严格来说,我认为object_id返回的对象地址并不是对象地址,但是唯一标识符应该可以解决OP的问题。
    • @maerics:在 MRI 中它确实可以(对于除整数、符号、true、false 和 nil 之外的所有对象)。
    • 嗯,也许在某些版本上;我最近的 MRI (1.8.7 darwin) 在默认 inspectobject_id 之间肯定显示不同的值。
    • maerics 似乎是正确的,至少在我的 Ruby 解释器中是这样。虽然整数、符号、true、false 和 nil 的 object_ids 肯定是特殊的(即,每次运行程序时它们都保持不变),但其他所有东西的 object_ids 都不等于对象地址。不过,它们是唯一可识别的,而且它是迄今为止最容易实施的解决方案,所以 +1。
    • @maerics:你说得对,object_id 返回(obj|FIXNUM_FLAG),即地址除以 2。不过很容易修复,只需将 object_id 乘以 2。
    【解决方案2】:

    这是不可能的。 Ruby 无法获取对象的内存地址,因为 Ruby 是一种内存安全的语言,它(根据设计)没有直接访问内存的方法。事实上,在 Ruby 的许多实现中,对象甚至没有内存地址。而在大多数确实将对象直接映射到内存的实现中,内存地址可能会在每次垃圾回收后发生变化。

    在当前版本的 MRI 和 YARV 中使用内存地址作为标识符意外起作用的原因是它们有一个糟糕的垃圾收集器实现,从不对内存进行碎片整理。所有其他实现都有垃圾收集器,它们进行内存碎片整理,从而在内存中移动对象,从而改变它们的地址。

    如果您将您的实现与内存地址联系起来,您的代码将只能在带有蹩脚垃圾收集器的慢速实现上运行。甚至不能保证 MRI 和 YARV 总是有蹩脚的垃圾收集器,事实上,在这两种实现中,垃圾收集器都被确定为主要的性能瓶颈之一,可以安全地假设对垃圾收集器进行更改。 YARV 的垃圾收集器在 SVN 中已经有了一些重大变化,这将成为 YARV 1.9.3 和 YARV 2.0 的一部分。

    如果您想要对象的 ID,请使用 Object#object_id

    【讨论】:

    • MRI/YARV 是否应该使用对象 ID 而不是内存地址进行检查?
    【解决方案3】:

    您的类实例可以将所需方法委托给一个类实例,而不是子类化 Array,这样您就不会继承被覆盖的 inspect 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 1970-01-01
      • 2020-12-14
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多