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.
我正在使用 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.