У меня возникли проблемы с записью большого набора данных в файл XML. Я использую следующий класс для сериализации объектов в XML, а затем записать их на диск:Как устранить утечку памяти в моем XMLSerializer/MemoryStream?
''' <summary>
''' Borrowed from http://icanmakethiswork.blogspot.ca/2012/11/xsdxml-schema-generator-xsdexe-taking.html
''' </summary>
''' <typeparam name="T"></typeparam>
''' <remarks></remarks>
Public Class XMLConverter(Of T)
Private Shared serializer As XmlSerializer = Nothing
''' <summary>
''' Static constructor that initialises the serializer for this type
''' </summary>
Shared Sub New()
serializer = New XmlSerializer(GetType(T))
End Sub
''' <summary>
''' Write a node to an xmlwriter
''' </summary>
''' <param name="writer"></param>
''' <param name="itemToAppend">the object to be converted and written</param>
''' <remarks></remarks>
Public Shared Sub AppendToXml(writer As XmlWriter, itemToAppend As T)
Dim strObj As String = ToXML(itemToAppend)
strObj = XMLCleaner.CleanResult(strObj)
writer.WriteRaw(strObj)
writer.Flush()
strObj = Nothing
End Sub
''' <summary>
''' Serialize the supplied object into a string of XML
''' </summary>
''' <param name="obj"></param>
''' <returns></returns>
Public Shared Function ToXML(obj As T) As String
Dim strXml As String = ""
Using memoryStream As New MemoryStream()
serializer.Serialize(memoryStream, obj)
memoryStream.Position = 0
Using sr As New StreamReader(memoryStream)
strXml = sr.ReadToEnd()
End Using
End Using
Return strXml
End Function
End Class
Public Class XMLCleaner
'This is just for removing junk and slightly modifying the output
Public Shared Function CleanResult(result As String) As String
Dim retVal As String = Regex.Replace(result, "\sxmlns.+?"".*?""", "")
retVal = Regex.Replace(retVal, "SavedSearchRecord", "Record")
retVal = retVal.Replace("<?xml version=""1.0""?>", "")
retVal = Regex.Replace(retVal, vbCrLf, vbCrLf & " ")
Return retVal
End Function
End Class
И зову это так:
XMLConverter(Of SavedSearchRecord).AppendToXml(writer, record)
Проблема в том, что память быстро накапливается, как я добавлять новые записи в файл и в конечном итоге приводить к исключению из памяти.
Я видел, что не кэширование сериализатора может привести к такому поведению, но я думаю, что я обошел эту проблему в своей реализации. (Пожалуйста, поправьте меня, если я ошибаюсь).
После изучения дампа памяти:
716821b4 28535 10497120 System.String
71682b74 140213 145562968 System.Char[]
71685670 140258 758802112 System.Byte[]
Я вижу, что у меня есть огромное количество байтовых массивов застревать в памяти. Данные в массивах заставляют меня думать, что они застряли в памяти с помощью функции ToXML (поскольку они содержат неизмененные сериализованные строки объектов).
Учитывая, что поток памяти находится в блоке Using, я не могу понять, почему эти байтовые массивы не собираются GC.
В дополнение к этому также имеется большое количество массивов Char в памяти (около 1/5 из памяти, используемой массивами байтов), которые не собираются.
Может ли кто-нибудь сказать мне, как предотвратить этот код от кульминации исключений из памяти?
FYI код написан с использованием .NET 4.0
Это не memstream, а все строки, которые вы создаете в этом классе. 'CleanResult' создает 4 на итерацию, но большой боров - это' ToXML', который воссоздает более длинные и длинные строки в результате сериализации. Вы в основном просто пытаетесь добавить элементы в файл, когда идете? – Plutonix
Это именно то, что я пытаюсь сделать. Я не понимаю, почему строки не собираются GC. Это потому, что это общий метод? Я бы подумал, что строки будут выпадать из области от вызова до звонка. – hobwell
Позвольте мне спросить по-другому: ** почему ** вы делаете это именно так - сериализатор вполне способен сериализовать все записи одновременно с гораздо меньшим количеством мусора строки. Я немного изменил класс и по-прежнему получил строки 200k-250k всего за 10k циклов. Делать это более прямолинейно было больше, чем 36MB за 100 000 повторений. Есть несколько причин, по которым это может быть так - например, сериализатор никогда не выходит за рамки сферы, и он является основной причиной; у вас может быть цикл, который создает их быстрее, чем может очистить. Сложно сказать. Дайте мне знать, если вы хотите увидеть альтернативный тестовый код 100k. – Plutonix