【IT168 技术文档】ninputer在这里(http://blog.joycode.com/ninputer/archive/2005/01/12/42866.aspx)有一篇blog提出了一个问题“值类型的Finalize不会被调用?”
我曾经对Rotor,也就是sscli(Shared Source Common Language Infrastructure),有过一些粗略的探索——不过现在由于比较忙,慢慢也半途而废了:)
这个问题可以从sscli里得到解释——sscli和目前运行在我们机器上的CLR实现差别主要在效率和扩展层面,因此研究它有助于理解CLR的行为。所有有关底层运作的代码都在目录sscli\clr\src\vm下。结合sscli的源码,下面我来聊聊这个话题。
首先给出一个结论:这是因为CLR对值类型进行了专门的设计,让它不可能进入Freachable Queue 里面。
下面根据sscli源码来对上述结论进行解释:
1。有关CLR类型一个最关键的类就是MethodTable。它的第一个字段m_wFlags(一个DWORD)的第21位 bit用来标示这个类是否有Finalizer。
MethodTable有一个方法为HasFinalizer就做此用:
MethodTable::HasFinalizer()
{
return (m_wFlags & enum_flag_HasFinalizer);
}
其中enum_flag_HasFinalizer = 0x100000,
GC在判断一个类型的实例对象是否需要放到Freachable Queue中,就是采用MethodTable::HasFinalizer()方法来判断。
2。最关键的是EEClass::BuildMethodTable,这个方法负责建立类型的方法表,它会被ClassLoader::LoadTypeHandleFromToken调用,ClassLoader::LoadTypeHandleFromToken又被ClassLoader::LoadTypeHandle和Module::BuildClassForModule调用。
用通俗的语言来解释就是“每一个类型被load到内存中的时候,它都会建立和该类型相关的方法表”,而我们在CLR中的所有对象都有自己的类型。
3。下面就是看EEClass::BuildMethodTable如何设置MethodTable::m_wFlags。
EEClass::BuildMethodTable中和“值类型的Finalize”这个主题相关的动作有以下几个调用(为简便起见我没有在这里写方法的参数):
EEClass::BuildMethodTable
{
...
CheckForValueType
...CheckForEnumType
...
GetMethodTable()->MaybeSetHasFinalizer...
}