使用Libxml2parsingXML时使用较大的RAM

我正在使用URLSessionDataTask从API下载XML文件。
XML看起来像这样:

<?xml version="1.0" encoding="UTF-8" ?> <ResultList id="12345678-0" platforms="A;B;C;D;E"> <Book id="1111111111" author="Author A" title="Title A" price="9.95" ... /> <Book id="1111111112" author="Author B" title="Title B" price="2.00" ... /> <Book id="1111111113" author="Author C" title="Title C" price="5.00" ... /> <ResultInfo bookcount="3" /> </ResultList> 

有时XML可能有数千本书。
我正在使用Libxml2中的SAXparsing器parsingXML。 在parsing时,我创build了一个对象Book并像这样设置了XML的值:

 private func startElementSAX(_ ctx: UnsafeMutableRawPointer?, name: UnsafePointer<xmlChar>?, prefix: UnsafePointer<xmlChar>?, URI: UnsafePointer<xmlChar>?, nb_namespaces: CInt, namespaces: UnsafeMutablePointer<UnsafePointer<xmlChar>?>?, nb_attributes: CInt, nb_defaulted: CInt, attributes: UnsafeMutablePointer<UnsafePointer<xmlChar>?>?) { let elementName = String(cString: name!) switch elementName { case "Book": let book = buildBook(nb_attributes: nb_attributes, attributes: attributes) parser.delegate?.onBook(book: book) default: break } } func buildBook(nb_attributes: CInt, attributes: UnsafeMutablePointer<UnsafePointer<xmlChar>?>?) -> Book { let fields = 5 /* (localname/prefix/URI/value/end) */ let book = Book() for i in 0..<Int(nb_attributes) { if let localname = attributes?[i * fields + 0], //let prefix = attributes?[i * fields + 1], //let URI = attributes?[i * fields + 2], let value_start = attributes?[i * fields + 3]//, /*let value_end = attributes?[i * fields + 4]*/ { let localnameString = String(cString: localname) let string_start = String(cString: value_start) //let string_end = String(cString: value_end) if let end = string_start.characters.index(of: "\"") { let value = string_start.substring(to: end) book.setValue(value, forKey: localnameString) } else { book.setValue(string_start, forKey: localnameString) } } } return book } 

在UITableViewController中, onBook(book: Book)委托方法将book对象附加到一个数组并更新UITableView。 到现在为止还挺好。

现在的问题是,它需要太多的设备的RAM,所以我的设备变得缓慢。 在XML中约500本书需要> 500 MB的RAM。 我不知道为什么。 当我在乐器中查找RAM时,我看到_HeapBufferStorage<_StringBufferIVars, UInt16>

仪器

多个条目大于100 KB

HeapBufferStorage条目 在事件历史logging中列出了buildBook()方法

事件历史

当我从构造函数XMLParser(contentsOf: URL)使用XMLParser从首先下载整个XML,然后parsing它,我有正常的RAM使用率。 不pipe有多less本书 但是我想在UITableView中尽快显示这些书籍。 我只想要像iOS的Android的XMLPullParser。

我正在使用libxml2(由于这个问题),并有这样的代码:

 xmlParseChunk(ctxt, data, Int32(read), 0) 

改变这个调用会大大减less内存消耗的数量:

 autoreleasepool { xmlParseChunk(ctxt, data, Int32(read), 0) } 

如果您使用上面的parsing器调用,这可能会解决您的问题。 如果没有,那么在autoreleasepool调用中包装你的委托调用可能会有所帮助。

原因是因为很多中间对象正在被创build并添加到自动释放池而不被释放。 看到这个职位了解更多详情。

另一种方法是通过以其他方式更改代码来减less添加到自动释放池的对象数量。 我发现,例如,我正在创造额外的string,在可以避免的地方修剪空白。

此外,这与您的问题无关,但属性的开始和结尾告诉您string的长度,您应该使用该string。

例如:

 let valStart = UnsafeMutableRawPointer(mutating: attributes! .advanced(by: 3 + Int(i * 5)).pointee) let valEnd = UnsafeMutableRawPointer(mutating: attributes! .advanced(by: 4 + Int(i * 5)).pointee) let valData = Data(bytesNoCopy: valStart!, count: valEnd! - valStart!, deallocator: .none) let attrValue = String(data: valData, encoding: String.Encoding.utf8)