Out of Memory bij verwerken grote bestanden
Bij het uitvoeren van een SQL-statement kan een OutOfMemoryException
optreden:
itgenclr007:
Application is using more memory than available.
Restarting the application, use 64-bit Windows and Office or making more memory available might resolve this problem.
Exception of type ‘System.OutOfMemoryException’ was thrown.
ccurred (UTC): 5/16/2022 6:23:04 AM
Alle Invantive SQL programmatuur is geschikt om in 64-bit modus te draaien en geeft daar ook de voorkeur aan. Het beschikbare werkgeheugen is daardoor meestal vele gigabytes en die worden ook automatisch gebruikt bij omvangrijke en massaal parallelle verwerking zoals op Invantive Cloud. De enige voorkomende uitzondering is bij gebruik binnen de 32-bit versie Microsoft Office; hierbij is het beschikbare geheugen meestal beperkt tot circa 1,5 GB.
Echter, de System.OutOfMemoryException
kan ook optreden als er ruim voldoende werkgeheugen beschikbaar is en een 64-bit versie uitgevoerd wordt.
Een individuele tekst in de Microsoft CLR voor .net heeft een maximale omvang van circa 2 GB (2^31) bytes. Uitgaande van 2 bytes per karakter is de limiet circa 1 miljard karakters. In de praktijk loopt men hier wel eens tegenaan bij het verwerken van omvangrijke JSON of XML-bestanden.
Een voorbeeld hiervan is het volgende Invantive SQL-statement dat alle bestanden met de extensie ‘trx’ (Visual Studio Test Results File) uitleest en omzet naar een tabelstructuur:
select xml.class_name
, xml.test_id
from files@os('c:\temp\vstest-output', '*.trx', false) fle
join xmltable
( '/*["TestRun"=local-name()]'
|| '/*["TestDefinitions"=local-name()]'
|| '/*["UnitTest"=local-name()]'
|| '/*["TestMethod"=local-name()]'
passing file fle.file_path
columns class_name varchar2 not null path '@className'
, test_id guid not null path '../@id'
) xml
Dit kan ook geschreven zijn met een read_file_text
als:
select xml.class_name
, xml.test_id
from versionelements@inmemorystorage vet
join files@os('${TEST_RESULTS_FOLDER}', '*.trx', false) fle
join tests@inmemorystorage tst
on fle.file_path like '%' || basename(tst.test_dll, '.dll') || '.trx'
join read_file_text@Os(fle.file_path) rfe
join xmltable
( '/*["TestRun"=local-name()]/*["TestDefinitions"=local-name()]/*["UnitTest"=local-name()]/*["TestMethod"=local-name()]'
passing rfe.file_contents
columns class_name varchar2 not null path '@className'
, test_id guid not null path '../@id'
) xml
Al bij een TRX-bestand van ruim 1 gigabyte zal een OutOfMemoryException
optreden, omdat het TRX-bestand als UTF8 is vastgelegd waarbij de veelvoorkomende karakters uit de ASCII-reeks maar 1 byte opslag vragen. Bij het uitlezen wordt dit automatisch omgezet in UTF-16, waardoor het geheugenbeslag voor de tekst al boven de 2 GB uitkomt.
Dit is terug te lezen in de call stack:
at System.String.CreateStringFromEncoding(Byte* bytes, Int32 byteLength, Encoding encoding)
at System.Text.UTF8Encoding.GetString(Byte[] bytes, Int32 index, Int32 count)
at lambda_method(Closure , GlobalState , ExecutionOptions , IQueryStatePerExecution , ISparseArray , ISparseArray )
at Invantive.Sql.V1.FirehoseResultSet.JB.MoveNext()
at Invantive.Sql.V1.FirehoseResultSet.HK.MoveNext()
at Invantive.Data.CompressedEnumerable`1.<GetEnumerator>d__10.MoveNext()
at Invantive.Sql.V1.FirehoseResultSet.JB.MoveNext()
...
De Microsoft-interne aanroep van UTF8Encoding
verzorgt deze omzetting.
Hoe los ik een itgenclr007
op?
De meest ideale oplossing is om eerst te upgraden naar versie 22.1.56 of nieuwer en dan nogmaals te proberen. Vanaf deze release zijn er faciliteiten toegevoegd om extreem grote tekstbestanden met data te verwerken.
De alternatieve aanpak is om de bestanden op te hakken in delen voor verwerking in Invantive SQL. Dit kan soms door het programma dat ze aanmaakt opdracht te geven per 100 megabyte een nieuw bestand te maken of door kleinere input aan te bieden. Als dat niet mogelijk is, dan is een externe hulpprogramma nodig dat het grote bestand uit elkaar haalt en als losse bestanden toevoegt. Soms kan een extern hulpprogramma gerealiseerd worden met commandoregel tools, maar soms kan dit niet doordat relevante tools ontbreken of de tools zelf geen bestanden groter dan 2 GB kunnen verwerken. Het laatste redmiddel is een programma te schrijven in een programmeertaal.