有没有一种方法可以在内存中压缩一个对象并透明地使用它?

10

我目前正在构建一个处理大量数据的分析应用程序。一个典型的情况看起来像这样:用户选择一个包含大约 600 个测量文件的文件夹,每个文件包含大约 40,000 到 100,000 个值。应用程序将这些值读入一个对象中,该对象在内部作为数据缓存工作,因此不必在每次访问时读取文件。

这很有效,但我注意到内存消耗非常高,最终可能会变得太大。在我的测试期间,当应用程序的内存消耗超过 2GB RAM 时,它崩溃了。

保存数据的数据结构尽可能简单,基本上只包含一些字典,以两级嵌套方式包含数据,没有什么复杂的东西。我想知道是否有一种方便的方法可以将这个对象以压缩形式存储在 RAM 中。我知道这会降低性能,但在我的情况下完全可以接受。

是否有一种方式可以让我像平常一样使用我的对象?还是我必须在我的对象内部实现压缩?

感谢您的建议!


2
编译成64位应用程序以避免2G限制。现在大多数计算机都有4GB以上的内存,不是吗? - Sergey Kalinichenko
1
@nicodemus: 64位.NET的限制可以被解除:http://msdn.microsoft.com/zh-cn/library/hh285054(v=vs.110).aspx - Martin Liversage
1
文件的原始数据有多大?如果磁盘IO真的是您的瓶颈,并且总文件大小可接受,那么只需将文件缓存在内存中可能是一个选项。 - Willem van Rumpt
1
感谢您在该主题上的评论和有趣的链接 - 但最初的问题是想了解通过压缩对象来减少内存消耗的可能性,而不是使应用程序使用更多RAM。 - Rob
2
数据可以被压缩吗?如果你有一百万个不同的数字,那么压缩就很难。但如果你有一百万个零和两个实际值,那么压缩似乎就容易了。 - nvoigt
显示剩余6条评论
3个回答

19

这取决于你所使用的类型。一种可能的方法是将对象压缩,将它们保留为压缩的byte[],而不是使用扩展方法的原始对象格式。

你还可以将其与x64位进程结合使用:

public static byte[] SerializeAndCompress(this object obj) 
{
    using (MemoryStream ms = new MemoryStream()) 
    using (GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true))
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(zs, obj);
        return ms.ToArray();
    }
}

public static T DecompressAndDeserialize<T>(this byte[] data)
{
    using (MemoryStream ms = new MemoryStream(data)) 
    using (GZipStream zs = new GZipStream(ms, CompressionMode.Decompress, true))
    {
        BinaryFormatter bf = new BinaryFormatter();
        return (T)bf.Deserialize(zs);
    }
}

是的,确实做到了 - 对于两年的延迟感到抱歉 :-) - Rob

3

"Yuval Itzchakov"的代码存在错误!他在关闭压缩器之前执行了ms.ToArray();

这将导致在DecompressAndDeserialize方法中出现错误。

以下代码可行:

public static byte[] SerializeAndCompress(this object obj)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(zs, obj);
                }
                return ms.ToArray();
            }

        }:

2

只有当我这样改变它时,它才起作用。使用上面的示例,我会得到一个“serializationexception未标记为可序列化”的错误。不要忘记在你的类中添加“[Serializable()]”。

public static byte[] SerializeAndCompress(this object obj) 
{
    var ms = new MemoryStream();
    using (GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true))
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(zs, obj);
    }
    return ms.ToArray();
}

public static T DecompressAndDeserialize<T>(this byte[] data)
{
    using (MemoryStream ms = new MemoryStream(data)) 
    using (GZipStream zs = new GZipStream(ms, CompressionMode.Decompress, true))
    {
        BinaryFormatter bf = new BinaryFormatter();
        return (T)bf.Deserialize(zs);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接