C#写入OSM(XML)遇System.OutOfMemoryException的解决咨询
解决方案:使用流式XML写入替代DOM方式
你的问题根源在于XmlDocument是基于DOM的API,会将整个XML文档的所有节点加载到内存中。当osmNodes数量庞大时,x86平台的内存限制(最大约2GB可用内存)无法容纳整个DOM树,从而抛出OutOfMemoryException。
改用XmlWriter(流式XML写入API)可以彻底解决这个问题,它不需要在内存中保留整个文档结构,而是边写边输出到文件/流,内存占用极低。
替换后的实现代码
// 配置XmlWriter的输出格式,匹配你的预期XML样式 var writerSettings = new XmlWriterSettings { Indent = true, IndentChars = " ", // 对应预期的缩进 Encoding = Encoding.UTF8, OmitXmlDeclaration = false // 如果不需要XML声明(<?xml ...?>),可以设为true }; // 直接写入到目标文件,也可以替换为MemoryStream等其他流 using (XmlWriter writer = XmlWriter.Create("output.osm", writerSettings)) { writer.WriteStartDocument(); // 写入根元素<osm>及属性 writer.WriteStartElement("osm"); writer.WriteAttributeString("version", "0.6"); writer.WriteAttributeString("upload", "false"); // 匹配预期输出的upload属性 // 循环写入每个<node>元素 foreach (var item in osmNodes) { writer.WriteStartElement("node"); writer.WriteAttributeString("id", item.Id.ToString()); writer.WriteAttributeString("lat", item.Lat.ToString()); writer.WriteAttributeString("lon", item.Lon.ToString()); writer.WriteEndElement(); // 闭合当前<node>标签 } writer.WriteEndElement(); // 闭合<osm>标签 writer.WriteEndDocument(); }
为什么这个方法有效?
- XmlWriter是向前只读的流式写入工具,每次仅处理当前要写入的元素,写完就释放相关内存,不会在内存中存储整个XML结构。
- 无论
osmNodes包含多少元素,内存占用都维持在很小的固定范围内,完全适配x86/AnyCPU平台的内存限制。
备选方案(若必须使用XmlDocument)
如果因为业务需求必须保留DOM操作,可以采用分批写入的方式:
- 每次处理一部分
osmNodes(比如每1000个为一批),添加到osmElement后将文档保存到临时文件。 - 清空
XmlDocument和osmElement,释放内存,再处理下一批。 - 最后将所有临时文件合并为最终的OSM文件。
不过这种方案复杂度高、效率低,优先推荐使用XmlWriter的流式写入方案。
内容的提问来源于stack exchange,提问作者Vinayak Pattar
相关产品推荐
相关产品推荐

