DotNetRDF:Graph 或 CompressingTurtleWriter 不释放内存

DotNetRDF: Graph or CompressingTurtleWriter does not release memory

我正在使用 dotnetRDF 框架和 C# 以海龟格式为患者导出图表,为每位患者创建一个海龟文件。在大约 400 名患者之后,该程序由于内存问题而停止。每个海龟文件在 2 - 150 MB 之间。程序运行100个病人后占用内存约4GB,运行500个病人后占用内存约19GB,如任务管理器所示

我在导出 class 中有一个函数,它从 MSSQL 服务器读取数据,创建图形,最后使用 CompressingTurtleWriter 创建一个带有图形的海龟文件。

private int ExportPatient(string SubjectPseudoId)    
{
    Graph exportGraph = new Graph();
    AddNamespaces(exportGraph);

    // for each type of predicate
    {
       // read data from SQL (SqlConnection, SqlCommand and reader are using the using(){} statement)
       // for each datareader
       {
          // save values in subjectvalue, predicatevalue, objectvalue strings

          switch (objecttype)
          {
             case "string":
                exportGraph.Assert(new Triple(exportGraph.CreateUriNode(prefixRessource + EncodeIRI(dataprovidervalue + "-" + semanticDefinition.ClassName + "-" + subjectvalue)),
                exportGraph.CreateUriNode(semanticDefinition.AttributePrefixId + ":" + semanticDefinition.AttributeName),
                exportGraph.CreateLiteralNode(objectvalue, new Uri(XmlSpecsHelper.XmlSchemaDataTypeString))));
                break;
             case "double":
                exportGraph.Assert(new Triple(exportGraph.CreateUriNode(prefixRessource + EncodeIRI(dataprovidervalue + "-" + semanticDefinition.ClassName + "-" + subjectvalue)),
                exportGraph.CreateUriNode(semanticDefinition.AttributePrefixId + ":" + semanticDefinition.AttributeName),
                exportGraph.CreateLiteralNode(objectvalue, new Uri(XmlSpecsHelper.XmlSchemaDataTypeDouble))));
                break;
             case "datetime":
                exportGraph.Assert(new Triple(exportGraph.CreateUriNode(prefixRessource + EncodeIRI(dataprovidervalue + "-" + semanticDefinition.ClassName + "-" + subjectvalue)),
                exportGraph.CreateUriNode(semanticDefinition.AttributePrefixId + ":" + semanticDefinition.AttributeName),
                exportGraph.CreateLiteralNode(objectvalue, new Uri(XmlSpecsHelper.XmlSchemaDataTypeDateTime))));
                break;
             case "uri":
                exportGraph.Assert(new Triple(exportGraph.CreateUriNode(prefixRessource + EncodeIRI(dataprovidervalue + "-" + semanticDefinition.ClassName + "-" + subjectvalue)),
                exportGraph.CreateUriNode(semanticDefinition.AttributePrefixId + ":" + semanticDefinition.AttributeName),
                exportGraph.CreateUriNode(prefixRessource + EncodeIRI(dataprovidervalue + "-" + semanticDefinition.Range + "-" + objectvalue))));  //
                break;
             default:
                log.Warn("undefined objecttype=" + objecttype, process, runConfig.Project);
                break;
          } // switch
      } // for each datareader
   } // for each predicate
   // all the triplets are added to the graph, write it to the turtle file now.

   CompressingTurtleWriter turtlewriter = new CompressingTurtleWriter(5, TurtleSyntax.W3C);
   turtlewriter.PrettyPrintMode = true;
   turtlewriter.Save(exportGraph, CreateFileName(SubjectPseudoId));
   
   // dispose of the graph class
   exportGraph.Dispose();

} 
// return control to the calling function to process the next patient
// take the next SubjectPseudoId and call the function again until array is processed.

到目前为止,我尝试过的是处置或完成 CompressingTurtleWriter,但这两种方法都不存在,即使 https://www.dotnetrdf.org/api/html/T_VDS_RDF_Writing_CompressingTurtleWriter.htm#! 建议 CompressingTurtleWriter 具有受保护的 Finalize() 方法。

Graph I Dispose() 退出函数前

我试图解决 .Net5.0 和 .Net Core 3.1 的问题,但行为是一样的。 我也尝试 运行 这个函数作为一个任务,但它没有改变内存问题。

我做了 运行 VS 诊断工具并在 exportGraph.Dispose(); 之后创建了一个快照,它在提取 15 之后显示:

Object Type                                     Count        Size(Bytes)    InclusiveSize (Bytes)
VDS.Common.Tries.SparseCharacterTrieNode<Uri>   5'823'385    326'109'560    1'899'037'768

提取 25 后:

Object Type                                     Count        Size(Bytes)    InclusiveSize (Bytes)
VDS.Common.Tries.SparseCharacterTrieNode<Uri>   11'882'772   665'435'232    1'540'054'160

在任务管理器中,程序在 25 次提取后使用 1'646'964 K,而在程序开始时使用大约 250'000 K。

25 个提取文件的总大小约为 302 MB。

我在我的代码中看不到任何问题,我想知道为什么还有很多 VDS.Common.Tries.SparseCharacterTrieNode<Uri> 仍在堆中?

有没有人有类似的经历或知道如何解决这个问题?

我认为问题在于 dotNetRDF 正在缓存在创建每个图形期间创建的所有 URI,并且该缓存是全局缓存。我建议在开始处理之前将 VDS.RDF.Options.InternUris 设置为 false - 这是一个全局设置,因此只需要在程序开始时完成一次。

您还可以通过选择简单索引(将 VDS.RDF.Options.FullTripleIndexing 设置为 false)或使用 NonIndexedGraph 而不是默认的 Graph 来减少每个单独图表的内存使用实现(这是假设您所做的只是生成然后序列化图形)。还有一些tips on reducing memory usage here.