gpt4 book ai didi

c# - 序列化/反序列化后使用的ram大小异常增加

转载 作者:太空宇宙 更新时间:2023-11-03 22:58:02 24 4
gpt4 key购买 nike

我使用以下方法在序列化后将应用程序数据保存到文件中,并在反序列化(en/decrypted)后从该文件加载数据。

private void SaveClassToFile(string fileAddress, string password, object classToSave)
{
const int ivSaltLength = 16;
byte[] salt = new byte[ivSaltLength];
byte[] iv = new byte[ivSaltLength];
byte[] codedClass = new byte[0];

iv = CreateIV();
salt = CreateSalt();

using (var memoryStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, classToSave);
codedClass = new byte[Convert.ToInt32(memoryStream.Length)];
memoryStream.Seek(0, SeekOrigin.Begin);

if (memoryStream.Read(codedClass, 0, Convert.ToInt32(memoryStream.Length)) != memoryStream.Length)
{throw new Exception("failed to read from memory stream"); }
}

using (SpecialCoderDecoder specialCoder = new SpecialCoderDecoder(SpecialCoderDecoder.Type.Coder, password, salt, iv))
{ specialCoder.Code(codedClass); }

using (FileStream streamWriter = new FileStream(fileAddress, FileMode.CreateNew))
using (BinaryWriter binaryWriter = new BinaryWriter(streamWriter))
{
binaryWriter.Write(salt);
binaryWriter.Write(iv);
binaryWriter.Write(codedClass);
}
}

private object LoadClassFromFile(string fileAddress, string password)
{
const int ivSaltLength = 16;
byte[] salt = new byte[ivSaltLength];
byte[] iv = new byte[ivSaltLength];
byte[] codedClass = new byte[0];
int codedClassLengthToRaed = 0;
FileInfo fileInfo;
object result = null;
fileInfo = new FileInfo(fileAddress);

using (FileStream streamWriter = new FileStream(fileAddress, FileMode.Open))
using (BinaryReader binaryreader = new BinaryReader(streamWriter))
{
salt = binaryreader.ReadBytes(ivSaltLength);
iv = binaryreader.ReadBytes(ivSaltLength);
codedClassLengthToRaed = Convert.ToInt32(fileInfo.Length) - (2 * ivSaltLength);
codedClass = binaryreader.ReadBytes(codedClassLengthToRaed);
}

using (SpecialCoderDecoder specialDecoder = new SpecialCoderDecoder(SpecialCoderDecoder.Type.Decoder, password, salt, iv))
{ specialDecoder.Decode(codedClass); }

using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
memoryStream.Write(codedClass, 0, codedClass.Length);

memoryStream.Seek(0, SeekOrigin.Begin);
result = (object)binaryFormatter.Deserialize(memoryStream);
}

return result;
}

如果应用程序中没有数据,我向其中添加了大约 100MB 数据(基于任务管理器)并保存。加载数据后,任务管理器显示应用程序数据约为200-400 MB!

为了将应用程序类封装到一个类中以使用此方法,我使用了如下类:

public class BigClass
{
public ClassA classA;
public ClassB classB;

public BigClass(ClassA a, ClassB b)
{
classA = a;
classB = b;
}
}

ClassAClassB(应该保存/加载的类)中的每一个都是这样的:

public class ClassA
{
List<ClassASub> list = new List<ClassASub>();

//some variables...

//some methodes

private class ClassASub
{
int intValue;
long longValue;
string stringValue;
Image image;

//some simple methodes....
}
}

我不谈论在序列化/反序列化过程中使用的 RAM 的大小。之后我会谈到使用过的 RAM,那时只有应用程序数据应该存在。

最佳答案

您正在将数据作为数组 (codedClass) 加载到内存中。根据您的指示,这个数组大概有 100MB 左右,这足以确保它被分配到大对象堆上。

现在:GC 旨在优化您的整体 系统性能;由于多种原因,它不是旨在不断积极地回收内存:

  • 如果您的系统中有大量可用内存(您没有内存压力)并且没有特定的收集需求,则这是不必要的开销
  • 一些数据的收集成本高于其他数据;其中最昂贵的是大对象堆,所以它排在队列的后面;其他内存
  • 释放
  • 即使数据是免费的,将这些页面释放回操作系统也不是必然有利的;该过程可以有效地决定保留它们以避免不断向操作系统请求内存并将其交还

在您的情况下,您可以尝试使用 System.GC 上的方法强制运行一个集合,但我认为真正的目标是不分配那些大数组。如果你能做任何事情来移动到 Stream基于模型而不是基于数组的模型,那会很好。这大概意味着改变 SpecialCoderDecoder显着。

要点:数组hard a hard cap的上限大小;您不能将当前实现扩展到 2GB 以上(即使启用了 <gcAllowVeryLargeObjects>)。

此外,我怀疑 BinaryFormatter正在加剧事情——它几乎总是如此。存在替代的更有效的陈旧序列化程序。减少序列化大小将是一个可供考虑的替代选项,而不是 - 或结合 - 移动到 Stream基于模型。

此外:您可以尝试使用压缩技术(GZipStreamDeflateStream 等)加密的有效负载中。您不应尝试压缩加密数据 - 您需要确保顺序是:

Serialize -> Compress -> Encrypt -> (storage) -> Decrypt -> Decompress -> Deserialize

序列化和压缩阶段已经完全Stream -兼容的。如果可以使加密层Stream -兼容,你就赢了。

关于c# - 序列化/反序列化后使用的ram大小异常增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44459083/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com