20.01.2023, 14:10 | #1 |
Участник
|
Сборка мусора, освобождение файлов (TextIo) и блокировки.
Всем привет.
Похоже я обнаружил интересный плавающий баг ядра по работе с файлами в аксапте. Принято считать что при вызове метода finalize() или при обнулении ссылки (а точнее всех ссылок) на файловую переменную в аксапте, ядро закрывает файл и высвобождает все ресурсы. Finalize & null Как бы не так. Выявился сценарий, при котором этого не происходит. Что еще хуже - высвобождение происходит, но с некоторой случайностью, может высвободиться сразу, может спустя несколько минут, а может и не высвободиться (но это редко, дольше 6 минут мы не ждали). Хотя в большинстве случаев все высвобождается нормально. Дано: Ax2012 R3 или ax4.0 (последний билд) Сервер аоса win 2016 server version 1607 (OS Build 14393.5427) Работает пакетная обработка (тестировали как в IL, так и в p-code) 1. Собирает информацию в аксапте. 2. Формирует в темп папке csv файл при помощи класса TextIo 3. Закрывает файл TextIo (finalize + обнуление файловой переменной, хотя после finalize она и так null) 4. Пакует csv файл в zip архив вызовом 7zip архиватора 5. Удаляет csv файл. 6. Кладет zip архив в базу аксапты. Таких пакетов 35 штук. Одновременно могут запускаться примерно до 10. Обнаружилась проблема: случайным образом архиватор при упаковке не может получить доступа csv файлу и поэтому создает пустой архив размером 22 байта. Как лечили а. Поставили в коде проверку (между пп 3 и 4) на размер архива, если слишком маленький, то удаляем его, ждем 5 секунд и все по новой. И так до 72 раз (6 минут). Конечно прикрутили запись логов, из которых видно, что иногда с первой попытки все успешно, иногда с 10-й, иногда с 35 а иногда и 72 не хватает. Тогда пакетная обработка вываливается в ошибку. В большинстве случаев все нормально. Получается, что в большинстве случаев файл отпускается сразу, но иногда спустя некоторое время. Иногда это время очень большое, так что мы не дожидались. При этом пока идут эти 72 разрешенные попытки, есть 6 минут посмотреть самим что там проиcходит. Тотал коммандер просмотрщиком csv файл на чтение открывает. Копировать тоже позволяет. Архиватор заархивировать не может. Пишет примерно так: Цитата:
c:\Program Files\Microsoft Dynamics AX\60\Server\YYY\bin>7za.exe a C:\Users\XXXX\AppData\Local\Temp\test-1.zip c:\Users\XXXX\AppData\Local\Temp\Article_2023-01-15_16-51-15.csv
7-Zip (a) [32] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04 Scanning the drive: 1 file, 12826 bytes (13 KiB) Creating archive: C:\Users\XXXX\AppData\Local\Temp\test-1.zip Items to compress: 1 WARNING: The process cannot access the file because it is being used by another process. c:\Users\XXXX\AppData\Local\Temp\Article_2023-01-15_16-51-15.csv Files read from disk: 1 Archive size: 22 bytes (1 KiB) WARNINGS for files: c:\Users\XXXX\AppData\Local\Temp\Article_2023-01-15_16-51-15.csv : The process cannot access the file because it is being used by another process. ---------------- WARNING: Cannot open 1 file Попробовал WinRar Та же проблема. Не может получить доступ к файлу. Запускал так Цитата:
c:\Program Files\Microsoft Dynamics AX\60\Server\YYY\bin>"c:\Program Files\WinRAR\WinRAR.exe" a -afzip -ep1 "c:\Users\XXXX\AppData\Local\Temp\Sorting_2023-01-15_18-41-46.csv_rar_ep1.zip" "c:\Users\XXXX\AppData\Local\Temp\Sorting_2023-01-15_18-41-46.csv"
Делал через System.IO.Compression.ZipFile как описано тут https://community.dynamics.com/ax/f/...les-in-ax-2012 в общем, проблема, похоже, не в архиваторах. Подумал, может проблема с файловой системой и темповая папка тормозит из-за большого числа мусорных файлов. Проверил - примерно 9 тысяч файлов было. Зачистил. Особой разницы не заметил. Ну, может чуть реже стало глючить. Антивируса, который мог бы блокировать в момент проверок, не было, отключили. В итоге заменили все вызовы TextIo на System.IO.StreamWriter Очистку ресурсов делаем как streamWriter.Close(); streamWriter.Dispose(); streamWriter = null; все заработало. Архиватор всегда пакует все с одной попытки. За 2 суток ни одной проблемы. |
|
|
За это сообщение автора поблагодарили: Ace of Database (3), _scorp_ (5), Товарищ ♂uatr (4), alex55 (1). |
20.01.2023, 14:58 | #2 |
Участник
|
Интересно, что пока решал проблему, нагуглил вот такое описание
Цитата:
https://blogs.msdn.microsoft.com/flo...x-and-the-clr/
The garbage collector in Dynamics Ax is very simple: it collects all unreferenced object every 3 seconds (ok, this is a little bit simplified, but it’s pretty much what the GC does). Consequently you know when the object is collected: about every 3 seconds and if this doesn’t happen you can use the Form SysHeapCheck to create a dump of the current heap, so you know how many references are currently held to that object. Another point that differentiates X++ with C# is the existing of a destructor. In X++ this destructor is called "finalize()". As described on Msdn: X++ objects are destructed automatically when there are no more references to them. You can destruct them explicitly in the following ways: - Use the finalize method. - Set the object handle to null. In X++ it's the finalize method that contains all code that is used to clean up the instance (releases all objects that are held by this instance, ...). In C# this is done by the Dispose() method, but I'll describe this later. An important point is mentioned in the Msdn documentation ( http://msdn.microsoft.com/en-us/libr...74(AX.10).aspx https://web.archive.org/web/20130517...8AX.10%29.aspx https://docs.microsoft.com/en-us/dyn...ectedfrom=MSDN ): Use finalize carefully. It will destruct an object even if there are references to it. Вероятнее всего это какой-то глюк в ядре аксапты, воспроизводимость которого зависит от ряда (неизвестных) случайных факторов. Видимо поэтому он и не исправлен до сих пор. |
|
20.01.2023, 15:57 | #3 |
Участник
|
Цитата:
Сообщение от Logger
Работает пакетная обработка (тестировали как в IL, так и в p-code)
1. Собирает информацию в аксапте. 2. Формирует в темп папке csv файл при помощи класса TextIo 3. Закрывает файл TextIo (finalize + обнуление файловой переменной, хотя после finalize она и так null) 4. Пакует csv файл в zip архив вызовом 7zip архиватора 5. Удаляет csv файл. 6. Кладет zip архив в базу аксапты. Обнаружилась проблема: случайным образом архиватор при упаковке не может получить доступа csv файлу и поэтому создает пустой архив размером 22 байта. Попробовал WinRar Та же проблема. Не может получить доступ к файлу. Код: -ssw : compress shared files -sse : stop archive creating, if it can't open some input file Цитата:
Последний раз редактировалось gl00mie; 20.01.2023 в 16:16. |
|
|
За это сообщение автора поблагодарили: Logger (15), Товарищ ♂uatr (4). |
20.01.2023, 16:07 | #4 |
Участник
|
Цитата:
Сообщение от Logger
Интересно, что пока решал проблему, нагуглил вот такое описание
Цитата:
In X++ it's the finalize method that contains all code that is used to clean up the instance (releases all objects that are held by this instance, ...). In C# this is done by the Dispose() method, but I'll describe this later.
Последний раз редактировалось gl00mie; 20.01.2023 в 16:09. |
|
20.01.2023, 16:17 | #5 |
Участник
|
Вот я это чувствовал!
Раз Total Commander мог файл просмотреть и скопировать, значит и архиватор должен был уметь. Не хватило терпения дочитать все описание ключей командной строки. Но, вообще, мне кажется, что безопаснее использовать .net классы для создания файлов. Если блокировка с файла не снята, то фиг знает, что там еще не доделано. Может не сделан flush на диск последней порции записываемых данных (хотя я это не проверял). |
|
Теги |
7zip, finalize, garbage collector, gc, rar, textio, winrar, архивирование |
|
|