重写方法时,如果没有 alias_method :old_method,:method,那么内存中是否还存在着之前方法的实现?还是说被覆盖了?
內存中還存在,但下一次 gc 之後就未必。ruby 每個類會有一個 hash table 用來存方法,確切地說是 id_table,因為 key 只能是 id(類似 symbol),id_table 的 value 就是方法。當你重新定義方法的時候,ruby 會用 id 在 id_table 裏找,然後直接替換掉舊的。在下一次 gc 的時候,ruby 會標記所有可達的對象,這時候 id_table 裏可達的只有你定義的新方法,舊的如果沒有被標記最後就會被回收。
非常感谢
答案:
alias 做的事情:将方法入口名,改为 新名字,更新方法环境变量(所在类)。新名字,最后引用原始的方法。
void rb_alias(VALUE klass, ID alias_name, ID original_name) { // 1)查找原始方法 // ..... orig_me = search_method(klass, original_name, &defined_class); // 2) 继承关键信息 // ..... // 如果原始方法是 super 方法(VM_METHOD_TYPE_ZSUPER),则将 klass 设置为其父类,并将 original_name 设置为原始方法的原始 ID,然后跳转到 again 标签重新查找原始方法。 // 如果原始方法是别名方法(VM_METHOD_TYPE_ALIAS),则获取原始方法的可见性,并将 orig_me 设置为原始方法的原始方法条目。断言原始方法的类型不是别名方法,以避免无限循环。 switch (orig_me->def->type) { case VM_METHOD_TYPE_ZSUPER: klass = RCLASS_SUPER(klass); original_name = orig_me->def->original_id; visi = METHOD_ENTRY_VISI(orig_me); goto again; case VM_METHOD_TYPE_ALIAS: visi = METHOD_ENTRY_VISI(orig_me); orig_me = orig_me->def->body.alias.original_me; VM_ASSERT(orig_me->def->type != VM_METHOD_TYPE_ALIAS); break; default: break; } // 处理特殊方法,边界 // ...... 省略 // 3)设置 方法 入口 // 调用 method_entry_set 函数在 target_klass 中为 alias_name 设置别名方法条目 // 并且设置关联属性 rb_method_entry_t *alias_me; alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner); RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass); if (RB_TYPE_P(target_klass, T_MODULE)) { // defined_class should not be set } else { RB_OBJ_WRITE(alias_me, &alias_me->defined_class, orig_me->defined_class); } }