以下这段代码是动态执行C#表达试,执行完后,内存资源没有释放,
public  object GetValue( string value,string eval)
{
string codeSnippet = "using System; " + "\r\n" +
"using System.Collections;"+
"namespace WrokFlowExpression {" + "\r\n" +
" public class Eval" + "\r\n" +
" {" + "\r\n" +
"       public Eval(){} " + "\r\n" +
"  public object GetValue()" + "\r\n" +
"  {" + "\r\n" +
"   " + eval +";"+
" " + "\r\n" +
" try{"+
"   return " + value + ";" + " \r\n " +
" }"+
" catch{ \r\n "+
" return false; \r\n }\r\n finally{ \r\n "+
" \r\n }"+
" return false; \r\n "+
"  }" + " \r\n" +
" } }";
CodeSnippetCompileUnit unit = new CodeSnippetCompileUnit( codeSnippet );  ICodeCompiler compiler =  new CSharpCodeProvider().CreateCompiler();
CompilerParameters para = new CompilerParameters();
para.ReferencedAssemblies.Add( "System.dll" );
para.GenerateInMemory = false;//这里改城true与false没有用
para.GenerateExecutable = false;
para.OutputAssembly = "Eval.dll";//这里输出内在与输出本地程序集也无效 Assembly asm = compiler.CompileAssemblyFromDom( para , unit ).CompiledAssembly; Type type = asm.GetType( "WrokFlowExpression.Eval" );
MethodInfo mi = type.GetMethod( "GetValue" , BindingFlags.Public | BindingFlags.Instance );  
object obj = asm.CreateInstance( "WrokFlowExpression.Eval" );
ParameterInfo[] parame = mi.GetParameters();
object[] ars = new object[parame.Length];
for(int i=0;i<parame.Length;i++)
{
// if(i==0) ars[i] = StartUser;
// if(i==1) ars[i] = CurrentUser;
// if(i==2) ars[i] = Entity;
// if(i>3)
// {
// ars[i] = null;
// }
}
return mi.Invoke(obj , ars );
}

解决方案 »

  1.   

    贴出我的:
    Imports System.Reflection
    Imports System.CodeDom
    Imports System.CodeDom.Compiler
    Imports Microsoft.CSharp
    Imports System.Windows.FormsPublic Class cCompiler
    #Region " 变量 "
    Private _CodeLanguage As enuCodeLanguage = mdlPublic.enuCodeLanguage.Default
    Private _lstErrors As ListView
    Private _hasError As Boolean = False
    Private _oAssembly As [Assembly]
    Private _Type As Type Private Provider As Object
    Private oCompiler As ICodeCompiler
    Private AsmNameString As String() = {"System.DLL", "System.Data.dll", "System.Windows.Forms.dll", "System.XML.dll", "Microsoft.VisualBasic.dll"} Private oCompParams As CompilerParameters
    #End Region#Region " 属性 "
    Friend Property CodeLanguage() As enuCodeLanguage
    Get
    Return _CodeLanguage
    End Get
    Set(ByVal Value As enuCodeLanguage)
    _CodeLanguage = Value
    End Set
    End Property Friend Property ListViewForErrors() As ListView
    Get
    Return _lstErrors
    End Get
    Set(ByVal Value As ListView)
    _lstErrors = Value
    End Set
    End Property Friend ReadOnly Property HasError() As Boolean
    Get
    Return _hasError
    End Get
    End Property Friend ReadOnly Property OutAssembly() As [Assembly]
    Get
    Return _oAssembly
    End Get
    End Property#End Region#Region " 私有方法 "
    Private Sub ListErrors(ByVal ErrorCollection As CompilerErrorCollection)
    If _lstErrors Is Nothing Then Return
    Dim i As Integer
    _lstErrors.Items.Clear()
    Dim pErr As CompilerError
    For i = 0 To ErrorCollection.Count - 1
    Dim pListItem As Windows.Forms.ListViewItem
    pErr = ErrorCollection.Item(i) If pErr.IsWarning Then
    pListItem = _lstErrors.Items.Add((i + 1).ToString, 1)
    Else
    pListItem = _lstErrors.Items.Add((i + 1).ToString, 0)
    End If
    'pListItem.SubItems.Add(pErr.FileName)
    pListItem.SubItems.Add(pErr.Line)
                pListItem.SubItems.Add(pErr.Column)
    pListItem.SubItems.Add(pErr.ErrorNumber)
    pListItem.SubItems.Add(pErr.ErrorText)
    Next End Sub Private Sub Init()
    If _CodeLanguage = mdlPublic.enuCodeLanguage.CSharp Then
    Provider = New Microsoft.CSharp.CSharpCodeProvider
    Else
    Provider = New Microsoft.VisualBasic.VBCodeProvider
    End If
    oCompiler = Provider.CreateCompiler()
    oCompParams = New CompilerParameters(AsmNameString)
    oCompParams.GenerateExecutable = False
    oCompParams.GenerateInMemory = True
    End Sub
    #End Region#Region " 公共方法 "
    Friend Function Compiler(ByVal StrSourceCode As String) As [Assembly]
    Dim oCodeUnit As CodeSnippetCompileUnit
    Dim oCompResults As CompilerResults
    oCodeUnit = New CodeSnippetCompileUnit(StrSourceCode)
    oCompResults = oCompiler.CompileAssemblyFromDom(oCompParams, oCodeUnit)   '开始编译 _oAssembly = Nothing
    If oCompResults.Errors.HasErrors Then
    ListErrors(oCompResults.Errors)
    _hasError = True
    Else
    Try
    _oAssembly = oCompResults.CompiledAssembly
    Return _oAssembly
    _hasError = False
    Catch ex As Exception
                    'Throw ex
                    cMsgBox(ex.Message)
                End Try
                _lstErrors.Items.Clear()
            End If
        End Function    Friend Function Run(ByVal ParamArray strParams As String()) As Boolean
            If _oAssembly Is Nothing Then Return False
            Dim oType As Type
            Dim sNameSpace, sTypeName As String
            Dim oMeth As MethodInfo
            For Each oType In _oAssembly.GetTypes            If oType.IsClass Then                'oMeth = oType.GetMethod("Main")
                    'If Not oMeth Is Nothing Then
                    sNameSpace = oType.Namespace
                    sTypeName = oType.Name
                    For Each oMeth In oType.GetMethods(BindingFlags.Public)
                        cMsgBox(oMeth.Name)
                    Next
                    Exit For
                    'End If
                End If
            Next
            Try
                If sTypeName <> "" Then
                    If sNameSpace <> "" Then sTypeName = sNameSpace & "." & sTypeName
                    Dim oObj As Object = _oAssembly.CreateInstance(sTypeName)
                    If strParams.Length > 0 Then oObj.main(strParams) Else oObj.main()
                End If
                Return True
            Catch ex As Exception
                Throw ex
                Return False
            End Try
        End Function    Friend Function GetOutType(ByVal typeName As String) As Type
            Try
                If _oAssembly Is Nothing Then Return Nothing
                Return _oAssembly.GetType(typeName)
            Catch ex As Exception
                Throw ex
                Return Nothing
            End Try
        End Function    Friend Function GetOutTypes(ByVal typeName As String) As Type()
            Try
                If _oAssembly Is Nothing Then Return Nothing
                Return _oAssembly.GetTypes
            Catch ex As Exception
                Throw ex
                Return Nothing
            End Try
        End Function
        Friend Function GetMethod(ByVal typeName As String, ByVal MethodName As String) As MethodInfo
            Try
                If _oAssembly Is Nothing Then Return Nothing
                Dim oType As Type = _oAssembly.GetType(typeName)
                Return oType.GetMethod("Main", BindingFlags.Public Or BindingFlags.InvokeMethod)
            Catch ex As Exception
                Throw ex
            End Try
        End Function#End Region#Region " 构造函数 "
    Public Sub New()
    Init()
    End Sub Public Sub New(ByVal CodeLanguage As enuCodeLanguage)
    _CodeLanguage = CodeLanguage
    Init()
    End Sub
    #End RegionEnd Class
      

  2.   

    GC回收内存是不可预判的,因此无法明确知道内存什么时候被回收。你的程序有两部分,
    一部分就是编译代码部分,首先用StringBuilder来替换string进行操作,
    其次如果是多次调用,把CodeSnippetCompileUnit和ICodeCompiler两个类型对象定义为成员,防止多个对象创建。第二部分是通过反射来调用,因此定义为成员不太合理,此时显示调用GC.Collect()来看看效果。
      

  3.   

    cool 也许你的代码需要优化........
      

  4.   

    非常感谢Knight94(愚翁) 回复。我先试试,对于动态编译所形成在内存或本地的程序集被当前应用域加载后,使用完后,如何卸载这个程序集了?微软并没有提供直接卸载这个程序集的方法,望Knight94(愚翁) 能指点。
      

  5.   

    问题依然存在,GC根本回收不了。动态编译是微软一个Bug???
    现在换了一种思路。卸载子域方式也不行,不明白,动态编译所占用的内存存在哪里??
    1、自己创建一个子域,用这个子域去载另一个程序集,则另一个程序集中的一个类实现动态编译功能。
    TestCompiler.dll程序集中的类代码如下:
    using System;
    using System.Reflection;
    using System.Windows.Forms;
    using System.Runtime.Remoting.Lifetime;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.Text;
    using Microsoft.CSharp;namespace TestCompiler
    {
    /// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    [System.Serializable]
    public class Eval
    {
    private CodeSnippetCompileUnit unit;
    private ICodeCompiler compiler;
    public Eval()
    {
    //
    // TODO: 在此处添加构造函数逻辑
    //
    } public  object GetValue( string value,string eval)
    { string codeSnippet = eval;
    StringBuilder MyStringBuilder = new StringBuilder(codeSnippet);
    unit = new CodeSnippetCompileUnit( MyStringBuilder.ToString() );  compiler =  new CSharpCodeProvider().CreateCompiler();
    CompilerParameters para = new CompilerParameters();
    para.ReferencedAssemblies.Add( "System.dll" );
    para.GenerateInMemory = false;
    para.GenerateExecutable = false;
    compiler.CompileAssemblyFromDom(para , unit );
    Assembly asm = compiler.CompileAssemblyFromDom( para , unit ).CompiledAssembly;
    Type type = asm.GetType( "WrokFlowExpression.Eval" );
    MethodInfo mi = type.GetMethod( "GetValue" , BindingFlags.Public | BindingFlags.Instance );  
    object obj = asm.CreateInstance( "WrokFlowExpression.Eval" );
    ParameterInfo[] parame = mi.GetParameters();
    object[] ars = new object[parame.Length];
    for(int i=0;i<parame.Length;i++)
    {
    // if(i==0) ars[i] = StartUser;
    // if(i==1) ars[i] = CurrentUser;
    // if(i==2) ars[i] = Entity;
    // if(i>3)
    // {
    // ars[i] = null;
    // }
    }
    obj = mi.Invoke(obj , ars );
    return obj;
    }
    }
    }
    2、在TestAssembly.dll程序中类TestClass中的代码如下:
    using System;
    using System.Reflection;
    using System.Windows.Forms;
    using System.Runtime.Remoting.Lifetime;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.Text;
    using Microsoft.CSharp;namespace TestAssembly
    {
    /// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    public class TestClass:MarshalByRefObject
    {
    protected string AssblPath = Application.StartupPath+@"\Bin\";
    protected int i=0;
    private CodeSnippetCompileUnit unit;
    private ICodeCompiler compiler;
    private Hashtable hash=new Hashtable();

    public TestClass()
    {

    }

    public string TestLoadAssembly(string Assemblyname)
    {
    Assembly Myassembly = Assembly.LoadFrom(AssblPath+ Assemblyname);
    return Myassembly.FullName;
    } public int GetCount()
    {
    return i++;
    }
    /// <summary>
    /// 重写InitializeLifetimeService
    /// 获取控制此实例的生存期策略的生存期服务对象
    /// </summary>
    /// <returns>生存期服务对象</returns>
    public override Object InitializeLifetimeService()
    {
    ILease lease = (ILease)base.InitializeLifetimeService();
    if (lease.CurrentState == LeaseState.Initial)
    {
    lease.InitialLeaseTime = TimeSpan.Zero;
    }
    return lease;
    } public  object GetValue( string value,string eval)
    {
    AppDomainSetup setup = new AppDomainSetup();            
    setup.ShadowCopyFiles = "true"; object obj = null;
    string codeSnippet = "using System; " + "\r\n" +
    "using System.Collections;"+
    "namespace WrokFlowExpression {" + "\r\n" +
    "[System.Serializable]"+
    " public class Eval" + "\r\n" +
    " {" + "\r\n" +
    "       public Eval(){} " + "\r\n" +
    "  public object GetValue()" + "\r\n" +
    "  {" + "\r\n" +
    "   " + eval +";"+
    " " + "\r\n" +
    " try{"+
    "   return " + value + ";" + " \r\n " +
    " }"+
    " catch{ \r\n "+
    " return false; \r\n }\r\n finally{ \r\n "+
    " \r\n }"+
    " return false; \r\n "+
    "  }" + " \r\n" +
    " } }";     string guids = Guid.NewGuid().ToString();
    AppDomain domain = AppDomain.CreateDomain(guids,null,setup);
    hash["1"]=domain;
    object objent = domain.CreateInstanceFromAndUnwrap("TestCompiler.dll","TestCompiler.Eval" );
    Type type = objent.GetType();
    MethodInfo mi = type.GetMethod( "GetValue" , BindingFlags.Public | BindingFlags.Instance );  
    // object obj = asm.CreateInstance( "WrokFlowExpression.Eval" );
    ParameterInfo[] parame = mi.GetParameters();
    object[] ars = new object[parame.Length];
    for(int i=0;i<parame.Length;i++)
    {
    ars[i] = codeSnippet;
    // if(i==0) ars[i] = StartUser;
    // if(i==1) ars[i] = CurrentUser;
    // if(i==2) ars[i] = Entity;
    // if(i>3)
    // {
    // ars[i] = null;
    // }
    }
    obj = mi.Invoke(objent , ars );
    GC.Collect();

    return obj;
    } public  object GetValue1( string value,string eval)
    {
    object val =  GetValue(value,eval);

    // if(domain!= null)
    // {
                    GC.Collect();
        AppDomain d=hash["1"] as AppDomain;
    hash.Remove("1");
    AppDomain.Unload(d);

    GC.Collect();
    // }
    return val;
    }
    在外面调用GetValue1,但每执行一次内存只涨不回收。郁闷啊
      

  6.   

    我大概测了一下,GC是可以回收的,不过需要手动做些处理。
    至于编译这部分,我没有单独去写,借用如下这个例子
    http://www.codeproject.com/dotnet/DynamicCompileAndRun.asp所做的第一个修改,修改其中的CompileEngine这个类,让它继承IDisposable这个接口,然后在接口函数中如下进行实现。
    #region IDisposable Members
    public void Dispose()
    {
    // TODO:  Add CompileEngine.Dispose implementation
    GC.SuppressFinalize( this );
    }
    #endregion第二个修改就是调用部分(FormMain.cs文件中)
    using( CompileEngine engine = new CompileEngine( code, language, entry ) )
    {
    engine.Run();
    }第三个修改就是线程开启(FormMain.cs文件中)
    GC.Collect();
    // we use a new thread to run it
    new Thread( new ThreadStart( RunTheProg ) ).Start();
    经过如上处理后,动态编译和运行所占用的资源不会立刻释放,不过再显式调用GC.Collect之后内存会降下来。你可以把上面的方法应用到你的程序当中,应该能满足你的要求。