8

这是一个非常疯狂的错误。以下是OutOfMemoryException针对非常短且简单的 XML 片段(例如,<ABC def='123'/>)抛出一个 , :

public static T DeserializeXmlNode<T>(XmlNode node)
{
    try
    {
        return (T)new XmlSerializer(typeof(T))
            .Deserialize(new XmlNodeReader(node));
    }
    catch (Exception ex)
    {
        throw; // just for catching a breakpoint.
    }
}

我在这篇 MSDN 文章中读到,如果我在构造函数中使用带有附加参数的 XmlSerializer,我最终会在每次调用它时生成未缓存的序列化程序程序集,从而导致Assembly Leak。但我没有在构造函数中使用额外的参数。它也发生在第一次在新启动的 AppDomain 中调用时,所以这也没有意义。

是什么赋予了?

4

4 回答 4

4

好吧,我的问题的最终答案不会帮助遇到这个问题的每个人,但我的一些同事在几个月后也遇到了在不同系统上使用不同产品的情况。几个月后,当他们在这里找到我的帖子并想知道我是否真的解决了它时,他们笑了,因为这里没有接受任何解决方案。

最终解决方案与反序列化问题无关。相反,它涉及完全卸载和安装 Oracle ODP.NET数据库客户端的全新副本,我们的许多应用程序都使用该提供程序。

根据轶事证据,这个问题似乎出现在未正确修补的 ODP.NET 程序集版本上,这些程序集随后通过虚拟机克隆传播到其他系统。

当 ODP.NET 被完全删除,从 Oracle 网站检索新的兼容版本并安装后,问题就完全消失了。

假设是可用(但已损坏)的 ODP.NET 驱动程序具有不安全的代码,并且Deserialize在首次使用后重复覆盖该方法附近的 .NET 受保护内存区域。如果Deserialize在任何 ODP.NET 调用之前调用它,它就可以正常工作。但是,在使用任何 ODP.NET 调用之后对 Deserialize 的所有后续调用都将失败。

现在已经在两个不同的产品中解决了两次这个问题的最终解决方案是安装一个良好/新鲜/干净/新的 ODP.NET 副本。

不漂亮......但这就是解决它的方法。

于 2011-02-16T22:11:19.233 回答
2

编辑:不幸的是,这不是解决方案,但它可以帮助其他人找到一个非常相似的问题。这里的答案是实际的解决方案。

相信我找到了解决这个问题的方法。这是.NET 3.5 SP1中的一个错误。

在 3.5 SP1 (ID:361615上,序列化挂起或抛出带有静态委托和 ISerializable 的 OutOfMemoryException :

当泛型类实现 ISerializable 并具有使用泛型类型参数的静态委托成员时,二进制反序列化挂起(在具有 Windows Server 2003 的 32 位系统上)或抛出 OutOfMemoryException(在具有 Windows Server 的 64 位系统上2008)。

.NET 3.5 SP1 会出现此错误,而没有 SP1 的 .NET 3.5 不会出现此错误。

解决方案是安装KB957543热修复程序。

于 2010-05-17T18:59:15.187 回答
1

您没有提供足够的详细信息来重现您的问题。但是,读者实现了 IDisposable 并且应该正确处理。最好将其包装在 using 块中。大多数开发人员在忘记处理某些东西时永远不会遇到问题,因为垃圾收集器最终会清理这些烂摊子。但是,在 GC 开始清理之前编写导致问题的代码并不难,甚至完全阻止清理。

public static T DeserializeXmlNode<T>(XmlNode node)
{
    XmlSerializer xs = new XmlSerializer(typeof(T));
    using(XmlNodeReader xr = new XmlNodeReader(node))
        return (T)xs.Deserialize(xr);
}
于 2010-05-12T22:47:49.160 回答
1

根据 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.
}
于 2010-05-13T13:41:10.277 回答