这似乎是System.Reflection.Emit中的实际内存泄漏。
下面的新解决方案
通过使用反射和手动处理过程,我可以消除大部分已用完的内存。我使用扩展方法在某些类型上添加了Dispose方法。这并不是全部清除,但代码显示了如何清除。我正以另一种方式取得我需要的结果。这里的代码是为那些对如何做感兴趣的人准备的。
在原始样本中,您将调用
tb.Dispose()
在生成类型后在typebuilder实例上执行。请记住,扩展方法如下
这不能把一切都清理干净
但是会释放大部分内存。此代码也没有针对速度进行优化。有很多方法可以加速反射的使用,这只是一个例子。
自担风险使用。
public static void Dispose(this TypeBuilder tb)
{
if (tb == null)
return;
Type tbType = typeof(TypeBuilder);
FieldInfo tbMbList = tbType.GetField("m_listMethods", BindingFlags.Instance | BindingFlags.NonPublic); //List<MethodBuilder>
FieldInfo tbDecType = tbType.GetField("m_DeclaringType", BindingFlags.Instance | BindingFlags.NonPublic);//TypeBuilder
FieldInfo tbGenType = tbType.GetField("m_genTypeDef", BindingFlags.Instance | BindingFlags.NonPublic);//TypeBuilder
FieldInfo tbDeclMeth = tbType.GetField("m_declMeth", BindingFlags.Instance | BindingFlags.NonPublic);//MethodBuilder
FieldInfo tbMbCurMeth = tbType.GetField("m_currentMethod", BindingFlags.Instance | BindingFlags.NonPublic);//MethodBuilder
FieldInfo tbMod = tbType.GetField("m_module", BindingFlags.Instance | BindingFlags.NonPublic);//ModuleBuilder
FieldInfo tbGenTypeParArr = tbType.GetField("m_inst", BindingFlags.Instance | BindingFlags.NonPublic); //GenericTypeParameterBuilder[]
TypeBuilder tempDecType = tbDecType.GetValue(tb) as TypeBuilder;
tempDecType.Dispose();
tbDecType.SetValue(tb, null);
tempDecType = tbGenType.GetValue(tb) as TypeBuilder;
tempDecType.Dispose();
tbDecType.SetValue(tb, null);
MethodBuilder tempMeth = tbDeclMeth.GetValue(tb) as MethodBuilder;
tempMeth.Dispose();
tbDeclMeth.SetValue(tb,null);
tempMeth = tbMbCurMeth.GetValue(tb) as MethodBuilder;
tempMeth.Dispose();
tbMbCurMeth.SetValue(tb, null);
ArrayList mbList = tbMbList.GetValue(tb) as ArrayList;
for (int i = 0; i < mbList.Count; i++)
{
tempMeth = mbList[i] as MethodBuilder;
tempMeth.Dispose();
mbList[i] = null;
}
tbMbList.SetValue(tb, null);
ModuleBuilder tempMod = tbMod.GetValue(tb) as ModuleBuilder;
tempMod.Dispose();
tbMod.SetValue(tb, null);
tbGenTypeParArr.SetValue(tb, null);
}
public static void Dispose(this MethodBuilder mb)
{
if (mb == null)
return;
Type mbType = typeof(MethodBuilder);
FieldInfo mbILGen = mbType.GetField("m_ilGenerator", BindingFlags.Instance | BindingFlags.NonPublic);
//FieldInfo mbIAttr = mbType.GetField("m_iAttributes", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo mbMod = mbType.GetField("m_module", BindingFlags.Instance | BindingFlags.NonPublic); //ModuleBuilder
FieldInfo mbContType = mbType.GetField("m_containingType", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo mbLocSigHelp = mbType.GetField("m_localSignature", BindingFlags.Instance | BindingFlags.NonPublic);//SignatureHelper
FieldInfo mbSigHelp = mbType.GetField("m_signature", BindingFlags.Instance | BindingFlags.NonPublic);//SignatureHelper
ILGenerator tempIlGen = mbILGen.GetValue(mb) as ILGenerator;
tempIlGen.Dispose();
SignatureHelper tempmbSigHelp = mbLocSigHelp.GetValue(mb) as SignatureHelper;
tempmbSigHelp.Dispose();
tempmbSigHelp = mbSigHelp.GetValue(mb) as SignatureHelper;
tempmbSigHelp.Dispose();
ModuleBuilder tempMod = mbMod.GetValue(mb) as ModuleBuilder;
tempMod.Dispose();
mbMod.SetValue(mb, null);
mbILGen.SetValue(mb, null);
mbContType.SetValue(mb, null);
mbLocSigHelp.SetValue(mb, null);
mbSigHelp.SetValue(mb, null);
mbMod.SetValue(mb, null);
}
public static void Dispose(this SignatureHelper sh)
{
if (sh == null)
return;
Type shType = typeof(SignatureHelper);
FieldInfo shModule = shType.GetField("m_module", BindingFlags.Instance | BindingFlags.NonPublic);
//FieldInfo shSig = shType.GetField("m_signature", BindingFlags.Instance | BindingFlags.NonPublic);
shModule.SetValue(sh, null);
//shSig.SetValue(sh, null);
}
public static void Dispose(this ILGenerator ilGen)
{
if (ilGen == null)
return;
Type ilGenType = typeof(ILGenerator);
FieldInfo ilSigHelp = ilGenType.GetField("m_localSignature", BindingFlags.Instance | BindingFlags.NonPublic);//SignatureHelper
SignatureHelper sigTemp = ilSigHelp.GetValue(ilGen) as SignatureHelper;
sigTemp.Dispose();
ilSigHelp.SetValue(ilGen, null);
}
public static void Dispose(this ModuleBuilder modBuild)
{
if (modBuild == null)
return;
Type modBuildType = typeof(ModuleBuilder);
FieldInfo modBuildModData = modBuildType.GetField("m__moduleData", BindingFlags.Instance | BindingFlags.NonPublic |BindingFlags.FlattenHierarchy );
FieldInfo modTypeBuildList = modBuildType.GetField("m__TypeBuilderList", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
ArrayList modTypeList = modTypeBuildList.GetValue(modBuild) as ArrayList;
if(modTypeList != null)
{
for (int i = 0; i < modTypeList.Count; i++)
{
TypeBuilder tb = modTypeList[i] as TypeBuilder;
tb.Dispose();
modTypeList = null;
}
modTypeBuildList.SetValue(modBuild, null);
}
modBuildModData.SetValue(modBuild, null);
}
编辑
找到实际原因:在动态程序集中创建的每个类型似乎都包含对
ModuleBuilder
(在
Type.Module
)它依次保存着
TypeBuilder
物体。每次添加类型以检查名称冲突时都会扫描此列表。如果你保持
HashSet
在类型生成例程之外,以确保没有任何名称冲突,可以在
模块构建器
私有变量
m__TypeBuilderList
之后
Type
不会产生任何负面影响(目前为止)