Как я могу предотвратить утечку памяти в CompileAssemblyFromSource?

#include <iostream>
#include <string>

using namespace std;

int main()
{
    cout << "Enter the number: ";
    int number;
    cin >> number;
    cout << "Enter names: ";
    string names;

    // USE peek() TO SOLVE IT! ;)
    if (cin.peek() == '\n') {
        cin.ignore(1 /*numeric_limits<streamsize>::max()*/, '\n');
    }

    getline(cin, names);

    return 0;
}

Просто загляните вперед, используя cin.peek(), и посмотрите, остается ли '\n' во внутреннем буфере cin. Если да: проигнорируйте его (в основном пропустите его)

30
задан Community 23 May 2017 в 12:10
поделиться

4 ответа

Выгрузка сборки не поддерживается. Некоторую информацию о причинах можно найти здесь . Некоторую информацию об использовании AppDomain можно найти здесь .

13
ответ дан 27 November 2019 в 23:51
поделиться

Вы также можете найти эту запись в блоге полезной: Использование AppDomain для загрузки и выгрузки динамических сборок. Он предоставляет пример кода, демонстрирующий, как создать домен приложения, загрузить в него (динамическую) сборку, выполнить некоторую работу в новом домене приложения, а затем выгрузить его.

Изменить: исправлена ​​ссылка, как указано в комментариях ниже.

8
ответ дан 27 November 2019 в 23:51
поделиться

Вы можете дождаться .NET 4.0? С его помощью вы можете использовать деревья выражений и DLR для динамической генерации кода без проблемы потери памяти при генерации кода.

Другой вариант - использовать .NET 3.5 с динамическим языком, таким как IronPython.

РЕДАКТИРОВАТЬ: Пример дерева выражений

1251] http://www.infoq.com/articles/expression-compiler

2
ответ дан 27 November 2019 в 23:51
поделиться

Думаю, у меня есть рабочее решение. Спасибо всем за то, что указали мне правильное направление (надеюсь).

Сборки нельзя выгружать напрямую, но можно использовать домены приложений. Я создал вспомогательную библиотеку, которая загружается в новый домен приложения и может скомпилировать новую сборку из кода. Вот как выглядит класс в этой вспомогательной библиотеке:

public class CompilerRunner : MarshalByRefObject
{
    private Assembly assembly = null;

    public void PrintDomain()
    {
        Console.WriteLine("Object is executing in AppDomain \"{0}\"",
            AppDomain.CurrentDomain.FriendlyName);
    }

    public bool Compile(string code)
    {
        CSharpCodeProvider codeProvider = new CSharpCodeProvider();
        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateInMemory = true;
        parameters.GenerateExecutable = false;
        parameters.ReferencedAssemblies.Add("system.dll");

        CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
        if (!results.Errors.HasErrors)
        {
            this.assembly = results.CompiledAssembly;
        }
        else
        {
            this.assembly = null;
        }

        return this.assembly != null;
    }

    public object Run(string typeName, string methodName, object[] args)
    {
        Type type = this.assembly.GetType(typeName);
        return type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, assembly, args);
    }

}

Он очень простой, но его было достаточно для тестирования. PrintDomain нужен, чтобы убедиться, что он действительно живет в моем новом домене приложений. Компиляция берет некоторый исходный код и пытается создать сборку. Run позволяет нам тестировать выполнение статических методов из данного исходного кода.

Вот как я использую вспомогательную библиотеку:

static void CreateCompileAndRun()
{
    AppDomain domain = AppDomain.CreateDomain("MyDomain");

    CompilerRunner cr = (CompilerRunner)domain.CreateInstanceFromAndUnwrap("CompilerRunner.dll", "AppDomainCompiler.CompilerRunner");            
    cr.Compile("public class Hello { public static string Say() { return \"hello\"; } }");            
    string result = (string)cr.Run("Hello", "Say", new object[0]);

    AppDomain.Unload(domain);
}

Она в основном создает домен, создает экземпляр моего вспомогательного класса (CompilerRunner), использует его для компиляции нового Assembly (скрытая), запускает некоторый код из этой новой сборки, а затем выгружает домен, чтобы освободить память.

Вы заметите использование MarshalByRefObject и CreateInstanceFromAndUnwrap.

32
ответ дан 27 November 2019 в 23:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: