ObjectContext утечка памяти для отдельных объектов - PullRequest
8 голосов
/ 03 октября 2011

Я уже проверил это с помощью профилировщика памяти, и в памяти не осталось реальных сущностей , но хеш-наборы, словари и объекты EntityKey - но я не нашел способа отключить эти ссылки.

Очень простой вопрос: как мне остановить контекст (или его ObjectStateManager) с , увеличивающимся в бесконечность в размере?контекстов следует избегать, но в этом случае это один комплексный прогон анализа, который требует загрузки нескольких иерархических данных (а приведенный ниже пример - просто минимальная демонстрация проблемы), так что, наконец, это «короткий» живой контекст одной операции.]

Шаги для воспроизведения:

  • создать новое консольное приложение
  • создать модель EF для базы данных Northwind (либо использовать настоящий SQL Server, либо скопировать Northwind.sdf из папки Compact Samples)
  • используйте код ниже:

Код [Обновлено, больше не требуется соединение с БД]:

class Program
{
    static void Main()
    {
        const double MiB = 1024 * 1024;
        using ( var context = new NorthwindEntities() )
        {
            var last = GC.GetTotalMemory(true) / MiB;
            Console.WriteLine("before run: {0:n3} MiB", last);
            var id = 0;
            while ( true )
            {
                Run(context, ref id);

                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                GC.WaitForPendingFinalizers();
                var current = GC.GetTotalMemory(true) / MiB;
                Console.WriteLine("after run: {0:n3} MiB (+{1:n3} MiB)", current, current - last);
                last = current;

                if ( Console.KeyAvailable )
                    break;
                Console.WriteLine(new string('-', 100));
            }
        }
    }

    static void Run(NorthwindEntities context, ref int id)
    {
        for ( int i = 0; i < 100000; i++ )
        {
            var category = new Category { Category_ID = ++id };
            category.EntityKey = new EntityKey("NorthwindEntities.Categories", "Category_ID", id);
            var product = new Product { Product_ID = id, Category_ID = id };
            product.EntityKey = new EntityKey("NorthwindEntities.Products", "Product_ID", id);
            product.Category = category;
            context.Attach(product);
            context.Detach(product);
            context.Detach(category);
        }

        var ctr = 0;
        Console.WriteLine("Enumerating living/attached objects:");
        const EntityState AllStates = EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged;
        foreach ( var entry in context.ObjectStateManager.GetObjectStateEntries(AllStates) )
            Console.WriteLine("  #{0} [{1}] {2}", ++ctr, entry.EntityKey, entry.Entity);
        if ( ctr == 0 )
            Console.WriteLine("  NOTHING (as expected)");
    }
}

Ответы [ 2 ]

1 голос
/ 07 октября 2011

Поскольку я только отсоединяю сущности непосредственно после вызова SaveChanges (), я теперь подсчитываю количество отсоединенных сущностей, и когда счетчик достигает 10000, я отсоединяю все еще живые (и необходимые) объекты от контекста и создаюновый контекст, к которому я присоединяю все отдельные объекты.Недостаток: свойство IsLoaded для EntityReferences и EntityCollections теперь всегда ложно (но я не полагаюсь на это).

0 голосов
/ 06 октября 2011

Я понимаю, что отсоединение предназначено для удаления контекста из сущности, а не сущности из контекста.Не доверяйте контексту, чтобы удалить ссылки на сущности (или их внутренние компоненты).

Я согласен, что утечка является проблемой, но многие люди (включая меня) пытались и не смогли предотвратить бесконечное увеличение контекста EF (пока выполняются запросы).

В качестве предложенного решения, возможно, вместо того, чтобы полагаться на базу данных в качестве «рабочего пространства» для своих расчетов, можно было бы воссоздать структуру базы данных в собственном представлении в памяти, поработать над этим и затем перевести обратно в db.Вы можете использовать временные файлы, если у вас много данных.

Это должно привести к сокращению продолжительности жизни контекстов.

В качестве альтернативы, возможно, стоит рассмотреть возможность использования чего-то другого, кроме EF (по крайней мере длячасти обработки), так как она может не подходить для вашей ситуации.Возможно, что-то более низкого уровня, например, DataReader, будет более подходящим для вашей ситуации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...