C# 内存流和大型对象堆
我必须使用WCF通过不可靠的连接在计算机之间传输大型文件 因为我希望能够恢复文件,并且我不希望WCF限制我的文件大小,所以我将文件分块成1MB的块。这些“块”以流的形式传输。到目前为止,效果相当不错 我的步骤是:C# 内存流和大型对象堆,c#,wcf,memory,out-of-memory,large-object-heap,C#,Wcf,Memory,Out Of Memory,Large Object Heap,我必须使用WCF通过不可靠的连接在计算机之间传输大型文件 因为我希望能够恢复文件,并且我不希望WCF限制我的文件大小,所以我将文件分块成1MB的块。这些“块”以流的形式传输。到目前为止,效果相当不错 我的步骤是: 打开文件流 将区块从文件读入字节[],并创建memorystream 转移块 回到2。直到整个文件被发送 我的问题在第二步。我假设,当我从字节数组创建内存流时,它将结束在LOH上,并最终导致outofmemory异常。我实际上不能制造这个错误,也许我的假设是错误的 现在,我不想发送消息
- 我当前的解决方案会在LOH上创建对象吗?这会给我带来问题吗李>
- 有没有更好的办法解决这个问题
for (int i = resumeChunk; i < chunks; i++)
{
byte[] buffer = new byte[chunkSize];
fileStream.Position = i * chunkSize;
int actualLength = fileStream.Read(buffer, 0, (int)chunkSize);
Array.Resize(ref buffer, actualLength);
using (MemoryStream stream = new MemoryStream(buffer))
{
UploadFile(stream);
}
}
for(int i=resumeChunk;i
我对你问题的第一部分不太确定,但关于更好的方法,你考虑过了吗?它允许通过http在后台下载文件。您可以为它提供http://或file://URI。它可以从中断点恢复,并使用http头中的RANGE方法以字节块的形式下载。Windows Update使用它。您可以订阅提供进度和完成信息的事件 我希望这没问题。这是我关于StackOverflow的第一个答案
是绝对的,如果chunksize超过85000字节,那么数组将在大型对象堆上分配。您可能不会很快耗尽内存,因为您正在分配和释放大小相同的连续内存区域,因此当内存填满时,运行时可以将新块装入旧的回收内存区域
我会有点担心数组。调整调用大小,因为这将创建另一个数组(请参阅)。如果actualLength==Chunksize,这是一个不必要的步骤,除了最后一个块之外,其他所有块都是这样。因此,我至少建议:
if (actualLength != chunkSize) Array.Resize(ref buffer, actualLength);
这将删除大量的分配。如果actualSize与chunkSize不相同,但仍然>85000,则新数组也将分配到大型对象堆上,这可能会导致其碎片化,并可能导致明显的内存泄漏。我相信,由于泄漏速度相当缓慢,实际内存耗尽仍然需要很长时间
我认为更好的实现是使用某种缓冲池来提供阵列。你可以自己滚动(这太复杂了),但WCF确实为你提供了一个。我已稍微重写了您的代码,以获得以下建议:
BufferManager bm = BufferManager.CreateBufferManager(chunkSize * 10, chunkSize);
for (int i = resumeChunk; i < chunks; i++)
{
byte[] buffer = bm.TakeBuffer(chunkSize);
try
{
fileStream.Position = i * chunkSize;
int actualLength = fileStream.Read(buffer, 0, (int)chunkSize);
if (actualLength == 0) break;
//Array.Resize(ref buffer, actualLength);
using (MemoryStream stream = new MemoryStream(buffer))
{
UploadFile(stream, actualLength);
}
}
finally
{
bm.ReturnBuffer(buffer);
}
}
BufferManager bm=BufferManager.CreateBufferManager(chunkSize*10,chunkSize);
for(inti=resumeChunk;i
这假设UploadFile的实现可以被重写,以整数表示要写入的字节数
我希望这有帮助
乔我想出了另一个解决办法,让我知道你的想法 因为我不想在内存中存储大量数据,所以我一直在寻找一种优雅的方法来临时存储字节数组或流 其思想是创建一个临时文件(您不需要特定的权限来执行此操作),然后将其与内存流类似地使用。使类成为一次性类将在临时文件使用后清理它
public class TempFileStream : Stream
{
private readonly string _filename;
private readonly FileStream _fileStream;
public TempFileStream()
{
this._filename = Path.GetTempFileName();
this._fileStream = File.Open(this._filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
}
public override bool CanRead
{
get
{
return this._fileStream.CanRead;
}
}
// and so on with wrapping the stream to the underlying filestream
另见。
发件人:
是一种MemoryStream替代品,为性能关键型系统提供卓越的性能。特别是,它被优化为执行以下操作:
- 通过使用池缓冲区消除大型对象堆分配
- 产生的第2代地面军事系统少得多,由于地面军事系统暂停的时间少得多
- 通过限制池大小来避免内存泄漏
- 避免内存碎片
- 提供出色的可调试性
- 提供性能跟踪的指标
// finally overrride the Dispose Method and remove the temp file
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
this._fileStream.Close();
this._fileStream.Dispose();
try
{
File.Delete(this._filename);
}
catch (Exception)
{
// if something goes wrong while deleting the temp file we can ignore it.
}
}