Это - действительно сумасшедшая ошибка. Следующее бросает OutOfMemoryException
, для отрывков XML, которые очень коротки и просты (например,
):
public static T DeserializeXmlNode(XmlNode node)
{
try
{
return (T)new XmlSerializer(typeof(T))
.Deserialize(new XmlNodeReader(node));
}
catch (Exception ex)
{
throw; // just for catching a breakpoint.
}
}
Я читал в этой статье MSDN, что, если бы я использовал XmlSerializer с дополнительными параметрами в конструкторе, я закончил бы тем, что генерировал некэшируемые блоки сериализатора каждый раз, когда это назвали, вызвав Утечку блока. Но я не использую дополнительные параметры в конструкторе. Это также происходит на первом разе, когда это называют в недавно запущенном AppDomain, так, чтобы не имел смысла также.
Что дает?
На основании документации класса XmlSerializer вы должны кэшировать XmlSerializer, иначе это может вызвать снижение производительности или утечку памяти.
Hashtable serializers = new Hashtable();
// Use the constructor that takes a type and XmlRootAttribute.
XmlSerializer s = new XmlSerializer(typeof(MyClass), myRoot);
// Implement a method named GenerateKey that creates unique keys
// for each instance of the XmlSerializer. The code should take
// into account all parameters passed to the XmlSerializer
// constructor.
object key = GenerateKey(typeof(MyClass), myRoot);
// Check the local cache for a matching serializer.
XmlSerializer ser = (XmlSerializer)serializers[key];
if (ser == null)
{
ser = new XmlSerializer(typeof(MyClass), myRoot);
// Cache the serializer.
serializers[key] = ser;
}
else
{
// Use the serializer to serialize, or deserialize.
}
Вы не предоставили достаточно сведений, чтобы воссоздать проблему. Но читатель реализует IDisposable и от него следует утилизировать должным образом. Желательно обернуть его в блок using. Большинство разработчиков никогда не сталкиваются с проблемой, когда забывают избавиться от чего-либо, потому что сборщик мусора в конечном итоге уберет беспорядок. Однако нетрудно закодировать что-то, что вызывает проблемы, до того, как сборщик мусора приступит к очистке, или даже полностью предотвратит очистку.
public static T DeserializeXmlNode<T>(XmlNode node)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
using(XmlNodeReader xr = new XmlNodeReader(node))
return (T)xs.Deserialize(xr);
}
EDIT: Это не было решением, к сожалению, но это может помочь другим отследить очень похожую проблему. Этот ответ здесь является фактическим решением.
Я верю, что нашел решение этой проблемы. Это ошибка в .NET 3.5 SP1.
Serialization hangs or throws an OutOfMemoryException with static delegate and ISerializable on 3. 5 SP1 (ID: 361615):
Когда общий класс реализует ISerializable и имеет статический член делегата, который использует аргументы общего типа, двоичная десериализация зависает (на 32-битной системе с Windows Server 2003) или выбрасывает OutOfMemoryException (на 64-битной системе с Windows Server 2008).
Эта ошибка возникает в .NET 3.5 SP1 и не возникала в .NET 3.5 без SP1.
Решением является установка KB957543 горячего исправления.