DataTable не выпускает память -- c# поле с участием memory поле с участием memory-management поле с участием datatable пол Связанный проблема

DataTable does not release memory


9
vote

проблема

русский

У меня есть процесс загрузки данных, который загружает большую сумму данных в DataTable, затем выполняет некоторые данные, но каждый раз, когда задание завершило dataLoader.exe (32bit, имеет предел памяти 1,5 г) не выпускает все Используется память.

Я попробовал 3 способа выпустить память:

  1. datatable.clear () Затем вызовите dataTable.dispose () (выпуск около 800 МБ памяти, но все еще увеличиваете на 200 мб память каждые время загрузки данных загрузки данных, после того, как 3 или 4 раза данных загрузки данных выброшены, потому что это превышает 1,5 г памяти в общей сложности)
  2. set dataTable на null (без выпуска памяти, а если выбрать загрузить больше данных, выброшенные с ошибкой памяти)
  3. call dataatable.dispose () непосредственно (не выпущено память, а если выбрать загрузить больше данных, выброшенные за из исключения памяти)

Ниже приводится код, который я пробовал для тестирования (в реальной программе не вызывается рекурсивно, он запускается некоторым каталогом, просмотрев логику. Этот код просто для тестирования. Извините за путаницу.):

 <код> using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data;  namespace DataTable_Memory_test { class Program {     static void Main(string[] args)     {         try         {             LoadData();                             Console.ReadKey();          }         catch (Exception ex)         {             Console.WriteLine(ex.ToString());             Console.ReadKey();         }     }      private static void LoadData()     {         DataTable table = new DataTable();         table.Columns.Add("Dosage", typeof(int));         table.Columns.Add("Drug", typeof(string));         table.Columns.Add("Patient", typeof(string));         table.Columns.Add("Date", typeof(DateTime));          // Fill the data table to make it take about 1 G memory.         for (int i = 0; i < 1677700; i++)         {             table.Rows.Add(25, "Indocin", "David", DateTime.Now);             table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);             table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);             table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);             table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);         }         Console.WriteLine("Data table load finish: please check memory.");         Console.WriteLine("Press 0 to clear and dispose datatable, press 1 to set datatable to null, press 2 to dispose datatable directly");         string key = Console.ReadLine();         if (key == "0")         {             table.Clear();             table.Dispose();             Console.WriteLine("Datatable disposed, data table row count is {0}", table.Rows.Count);             GC.Collect();                long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes             Console.WriteLine(lMemoryMB);          }         else if (key == "1")         {             table = null;             GC.Collect();             long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes             Console.WriteLine(lMemoryMB);         }         else if (key == "2")         {             table.Dispose();             GC.Collect();             long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes             Console.WriteLine(lMemoryMB);         }         Console.WriteLine("Job finish, please check memory");         Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");          key = Console.ReadLine();         if (key == "0")         {             Environment.Exit(0);         }         else if (key == "1")         {             LoadData();         }     }   } }   
Английский оригинал

I have a data loading process that load a big amount of data into DataTable then do some data process, but every time when the job finished the DataLoader.exe(32bit, has a 1.5G memory limit) does not release all the memory being used.

I tried 3 ways to release memory:

  1. DataTable.Clear() then call DataTable.Dispose() (Release about 800 MB memory but still increase 200 MB memory every time data loading job finish, after 3 or 4 times of data loading, out of memory exception thrown because it exceeds 1.5 G memory in total)
  2. Set DataTable to null (No memory released, and if choose load more data, out of memory exception thrown)
  3. call DataTable.Dispose() directly (No memory released, and if choose load more data, out of memory exception thrown)

Following is the code I tried for testing(In the real program it is not called recursively, it is triggered by some directory watching logic. This code is just for testing. Sorry for the confusion.):

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data;  namespace DataTable_Memory_test { class Program {     static void Main(string[] args)     {         try         {             LoadData();                             Console.ReadKey();          }         catch (Exception ex)         {             Console.WriteLine(ex.ToString());             Console.ReadKey();         }     }      private static void LoadData()     {         DataTable table = new DataTable();         table.Columns.Add("Dosage", typeof(int));         table.Columns.Add("Drug", typeof(string));         table.Columns.Add("Patient", typeof(string));         table.Columns.Add("Date", typeof(DateTime));          // Fill the data table to make it take about 1 G memory.         for (int i = 0; i < 1677700; i++)         {             table.Rows.Add(25, "Indocin", "David", DateTime.Now);             table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);             table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);             table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);             table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);         }         Console.WriteLine("Data table load finish: please check memory.");         Console.WriteLine("Press 0 to clear and dispose datatable, press 1 to set datatable to null, press 2 to dispose datatable directly");         string key = Console.ReadLine();         if (key == "0")         {             table.Clear();             table.Dispose();             Console.WriteLine("Datatable disposed, data table row count is {0}", table.Rows.Count);             GC.Collect();                long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes             Console.WriteLine(lMemoryMB);          }         else if (key == "1")         {             table = null;             GC.Collect();             long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes             Console.WriteLine(lMemoryMB);         }         else if (key == "2")         {             table.Dispose();             GC.Collect();             long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes             Console.WriteLine(lMemoryMB);         }         Console.WriteLine("Job finish, please check memory");         Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");          key = Console.ReadLine();         if (key == "0")         {             Environment.Exit(0);         }         else if (key == "1")         {             LoadData();         }     }   } } 
</div
           
       
       

Список ответов

4
 
vote

Ваша главная проблема - это поведение сборщика мусора отличается в зависимости от того, если вы отладки или в режиме выпуска без отладчика присутствуют.

Когда в сборке отладки или сборки выпуска с отладчиком, присутствующим, все объекты имеют свои жизненные жизни, распространяются на всю жизнь метода. Что это значит <код> int f1(int *a, int c) { *a = c - 2; /* <-- */ c = c*2 - (*a); printf("a= %d c= %d ", *a, c); return c - *a; } 2 не может быть восстановлена ​​GC, пока вы не выполнили <код> int f1(int *a, int c) { *a = c - 2; /* <-- */ c = c*2 - (*a); printf("a= %d c= %d ", *a, c); return c - *a; } 3 метода. Вот почему вы продолжаете выходить из памяти.

Если вы измените свою программу в режим выпуска и запустите его без отладчика, то, как только вы передадите последнюю ссылку на объект, переменная <код> int f1(int *a, int c) { *a = c - 2; /* <-- */ c = c*2 - (*a); printf("a= %d c= %d ", *a, c); return c - *a; } 4 указывает на ваш код кода, объект становится подходящим образом Для сборки мусора, и вы освободите память.

Причина, по которой GC меняется, это поведение во время «отладочной ситуации», подумайте о сам отладчике в качестве ссылки на все переменные, находящиеся в объеме текущего выполняющегося кода. Если бы он не смог бы не смог посмотреть значение переменной в окне Watch или Masing Over Over. Из-за того, что вы не можете «пройти последнюю ссылку на объект», пока переменная не выйдет из объема, либо вы перезаписываете переменную.

Смотрите в блоге posting на сборку мусора, область Срок службы объекта Для получения более подробной информации о процессе.

 

Your main problem is the behavior of the Garbage Collector is different depending on if you are debugging or in release mode without a debugger present.

When in a debug build or a release build with a debugger present all objects have their lifetimes extended to the entire lifetime of the method. What this means is table can not be reclaimed by the GC until you have completed the LoadData method. This is why you keep running out of memory.

If you change your program in to release mode and run it without the debugger then as soon as you pass the last reference to the object the variable table points to in your code path the object becomes eligible for garbage collection and you get the memory freed.

The reason the GC changes it's behavior during a "debuggable situation" is think of the debugger itself as holding a reference to all variables that are in scope of the currently executing code. If it did not you would not be able to look at the value of a variable in the watch window or mousing over it. Because of that you can not "pass the last reference to the object" until the variable goes out of scope or you overwrite the variable.

See the blog posting On Garbage Collection, Scope and Object Lifetimes for more detailed information about the process.

</div
 
 
3
 
vote

Если вы переместите роль, когда вы просите подтвердить за пределами функции, память освобождается правильно (только тестированный метод 1 (прозрачный и распоряжен)):

 <код> static void Main(string[] args) {     try     {         string key;         do         {             LoadData();             Console.WriteLine("Job finish, please check memory");             Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");             key = Console.ReadLine();         } while (key == "1");     }     catch (Exception ex)     {         Console.WriteLine(ex.ToString());         Console.ReadKey();     } }   

Возможно, память объектов освобождается, когда они не имеют возможности

 

If you move the part when you ask to reiterate outside of the function, the memory is freed correctly (only tested method 1(Clear and Dispose)):

static void Main(string[] args) {     try     {         string key;         do         {             LoadData();             Console.WriteLine("Job finish, please check memory");             Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");             key = Console.ReadLine();         } while (key == "1");     }     catch (Exception ex)     {         Console.WriteLine(ex.ToString());         Console.ReadKey();     } } 

Probably, the objects' memory is freed when they are out of scope

</div
 
 
         
         
1
 
vote

Там не совсем способ заставить C #, чтобы выпустить память, поскольку вы будете с кодом, у которого нет управления памятью. Это помогает понять, как работает коллектор мусора .NET. В основном использование памяти в приложениях .NET поднимается в одно из трех условий, которые вызывают сборку мусора. Я опишу процесс в ответе на следующий вопрос:

Очистка переменных в методах

Один из способов избежать OutOfMemory Исключение - это использовать MemoryFailPoint класс, который позволяет устанавливать точку отказа, за которым <код> InsufficientMemoryException брошен, давая вам возможность замедлить процесс, пока не будет доступен другой рабочей нити. Я не уверен, что это то, что вы хотите попробовать, но это доступно для вас:

https://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint%28v=vs.100%29.aspx?f=255&mspperror=-2147217396

 

There's not really a way to force C# to release memory as you would with code that doesn't have memory management. It helps to understand how the .NET garbage collector works. Basically memory usage in .NET apps rises to one of three conditions which trigger a garbage collection. I describe the process in the answer to the following question:

Cleaning up variables in methods

One way to avoid the OutOfMemory exception is to utilize the MemoryFailPoint class, which allows you to set a fail point beyond which an InsufficientMemoryException is thrown, giving you an opportunity to slow down the process until another worker thread is available. I'm not sure if this is something you'd want to try, but it's available to you:

https://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396

</div
 
 
         
         
1
 
vote
vote
Лучший ответ
 

В конце концов я обнаружил, что эта таблица данных не выпустила ошибку памяти, была вызвана копией Oracle Bulk. На всякий случай кто-то получил ту же проблему. Пожалуйста, смотрите следующее сообщение для справки

OracleBulkcopy Утечка памяти (Исключение)

 

Eventually I found this Data table not release memory bug was caused by Oracle bulk copy. Just in case some one got the same problem. Please see following post for reference

OracleBulkCopy Memory Leak(OutOfMemory Exception)

</div
 
 

Связанный проблема

1  Visual Studio C # KeyDown блокирует друг друга  ( Visual studio c sharp keydown blocking each other ) 
Есть ли способ сделать два ключа работать одновременно, поэтому они не блокируют друг друга? <код> private void multiplayer_KeyDown(object sender, KeyEv...

0  Тест подразделения для класса банка в C #  ( Unit test for bank class in c sharp ) 
Я учусь создавать модульные тесты для проекта, написанного в C #. Я был следовать примеру на веб-сайте MSDN, и теперь я только что застрял на том, как создать...

2  Несколько клиентских проектов на один серверный проект W / Silverlight & Ria Services Beta  ( Multiple client projects to one server project w silverlight ria services bet ) 
Тип или имя пространства имен «Ресурсы» не существует в «MyWebProject.Web» (Вы пропустите сборку Ссылка?) C: users ... mysecondproject generated_...

0  Сообщение об ошибке Wile пытается открыть файл .xls  ( Error message wile trying to open xls file ) 
Я создаю файл Excel на лету для отправки его вложение в электронном письме. Соответствующий фрагмент кода приведен ниже (это консольное приложение) <код> pu...

1  Получение релевантности упорядоченный результат из текстового запроса на коллекции MongoDB с использованием драйвера C #  ( Retrieve relevance ordered result from text query on mongodb collection using th ) 
Я пытаюсь отправить текстовые запросы коллекции и получить результаты в текстовом порядке. документы объяснить довольно хорошо, как это сделать в оболочке: ...

0  Написание одного символа за раз в приложении консоли C #?  ( Writing one character at a time in a c sharp console application ) 
Я не уверен, как это объяснить ... В основном я хочу иметь возможность писать строки текста в консоли, как старые RPG, используемые для записи диалога, один...

0  Не читайте текстовые данные на таблицу SQL в C #  ( Not reading text data to sql table in c sharp ) 
Поэтому я следовал большему количеству помощи, которую я мог найти здесь. Я создал программу C #, которая читает из текстового файла и вставляет в таблицу баз...

5  Использование Litjson в Unity3D  ( Using litjson in unity3d ) 
2 вопроса. 1) Можно ли использовать библиотеку Litjson AS так же, как и сценарии в JavaScript? Это действительно общий вопрос о том, чтобы иметь возможность...

0  Создание ссылки IPC между плагинами APC Java и C #  ( Establishing ipc link between a java app and c based plugins ) 
У нас есть приложение Java, а также ряд плагинов C #, для других приложений (например, Excel), которые могут взаимодействовать с основным приложением. Слой св...

0  Анимация спрайты в XNE после мыши  ( Sprite animation in xna following the mouse ) 
Моя старая проблема заключалась в том, что мой код изначально следит за мышью, но когда она достигла мыши, она исчезла, и в конечном итоге исчезла. Моя теку...

3  C # PropertiveGrid Drag Drop  ( C sharp propertygrid drag drop ) 
Я пытаюсь реализовать поддержку перетаскивания / падения на свойств в C # с использованием VS2005 (.NET 2.0). Собственность могут обрабатывать драгерацию и т....

5  сериализовать два разных экземпляра в списке на одну строку JSON  ( Serialize two different instances in a list to a single json string ) 
У меня есть два типа классов: <код> public class HolidayClass { public int ID { get; set; } public string Name { get; set; } public DateTime Sta...

0  Соединение не было закрыто. Текущее состояние соединения открыто  ( Connection was not closed connections current state is open ) 
Это дает сообщение об ошибках не было закрыто. Текущее состояние соединения открыто. Пожалуйста, помогите с кодом. <код> private void comboBox1_SelectedIn...

1  Получение строки сразу после вставки возвращается нет результата  ( Getting row right after insert returns no result ) 
Я бегут тесты подразделения, и когда я пытаюсь вставить данные в базу данных и получить его сразу после того, как я ничего не получаю (я пробовал с <код> Data...

0  Как загрузить каталог на FTP, используя ftplib?  ( How to upload directory to ftp using ftplib ) 
У меня проблемы с загрузкой Все файлы на FTP: я использую ftplib . У меня есть функция для загрузки: <код> Proj executable not found. Please set PROJ_DIR v...

Связанный проблема

1  Visual Studio C # KeyDown блокирует друг друга 
0  Тест подразделения для класса банка в C # 
2  Несколько клиентских проектов на один серверный проект W / Silverlight & Ria Services Beta 
0  Сообщение об ошибке Wile пытается открыть файл .xls 
1  Получение релевантности упорядоченный результат из текстового запроса на коллекции MongoDB с использованием драйвера C # 
0  Написание одного символа за раз в приложении консоли C #? 
0  Не читайте текстовые данные на таблицу SQL в C # 
5  Использование Litjson в Unity3D 
0  Создание ссылки IPC между плагинами APC Java и C # 
0  Анимация спрайты в XNE после мыши 
3  C # PropertiveGrid Drag Drop 
5  сериализовать два разных экземпляра в списке на одну строку JSON 
0  Соединение не было закрыто. Текущее состояние соединения открыто 
1  Получение строки сразу после вставки возвращается нет результата 
0  Как загрузить каталог на FTP, используя ftplib?