[英]Out of memory exceptions when using MemoryStream in cache
我们正在处理很多文件,大多数情况下需要打开和关闭这些文件才能读取数据。 将每个文件的内存流缓存在临时哈希表或其他对象中是个好主意吗?
当打开超过100MB的文件时,我们已经注意到内存不足异常。 我们正在使用wpf应用程序。
我们可以成功打开文件1到2次,有时3到4次,但是之后我们遇到了内存不足的异常。
如果您当前正在缓存这些文件,那么您会期望很快耗尽内存。
如果您尚未缓存它们,请不要这样做,因为那样只会使情况变得更糟。 也许您有内存泄漏? 使用完内存流后,您是否要对其进行处置?
处理大文件的最佳方法是使用FileStreams进行数据流的输入和输出,因此您不必一次将整个文件都保存在内存中。
如果在正常情况下和/或信息很少的情况下缓存文件内容,则说“是”或“否”非常困难。 但是,有限的资源是真实的世界,您(作为开发人员)必须对此加以考虑。 如果要缓存某些内容,则应使用某种机制来自动卸载数据。 在.NET Framework中,您可以使用WeakReference类,该类卸载目标对象(字节数组和内存流也是对象)。
如果您拥有硬件控制权,并且可以使用64位并且有很大的RAM资金,则可以缓存大文件。
但是,您应该对资源(cpu,ram)保持谦逊,并使用“便宜”的实现方式。
我认为问题在于,完成后,该文件没有立即处置,它正在等待下一个GC周期。
流是IDisposposable的,这意味着您可以并且应该使用using块。 那么当您处理完该流后,该流将立即处理。
我不认为缓存这样的数据量不是一个好的解决方案,即使您不会出现内存溢出。 签出“内存映射文件”解决方案,这意味着文件位于文件系统上,但读取速度几乎等于内存中的速度(肯定会有开销)。 查看此链接。 MemoryMappedFiles
PS Ther是关于互联网上这个主题的相当不错的文章和示例。 祝好运。
MemoryStream的一个问题是,每次强制增加容量时,内部缓冲区的大小都会加倍。 即使您的MemoryStream是100MB,文件是101MB,只要您尝试将最后1MB写入MemoryStream,MemoryStream上的内部缓冲区就会加倍到200MB。 如果为内存缓冲区提供的启动容量等于文件的启动容量,则可以减少此开销。 但这仍将允许文件使用所有内存,并在某些文件加载后停止任何新分配。 如果创建一个在WeakReference对象内提供帮助的缓存对象,您将能够允许垃圾收集器根据需要抛弃一些缓存文件。 但是不要忘记,您将需要添加代码以根据需要重新创建丢失的缓存。
public class CacheStore<TKey, TCache>
{
private static object _lockStore = new object();
private static CacheStore<TKey, TCache> _store;
private static object _lockCache = new object();
private static Dictionary<TKey, TCache> _cache =
new Dictionary<TKey, TCache>();
public TCache this[TKey index]
{
get
{
lock (_lockCache)
{
if (_cache.ContainsKey(index))
return _cache[index];
return default(TCache);
}
}
set
{
lock (_lockCache)
{
if (_cache.ContainsKey(index))
_cache.Remove(index);
_cache.Add(index, value);
}
}
}
public static CacheStore<TKey, TCache> Instance
{
get
{
lock (_lockStore)
{
if (_store == null)
_store = new CacheStore<TKey, TCache>();
return _store;
}
}
}
}
public class FileCache
{
private WeakReference _cache;
public FileCache(string fileLocation)
{
if (!File.Exists(fileLocation))
throw new FileNotFoundException("fileLocation", fileLocation);
this.FileLocation = fileLocation;
}
private MemoryStream GetStream()
{
if (!File.Exists(this.FileLocation))
throw new FileNotFoundException("fileLocation", FileLocation);
return new MemoryStream(File.ReadAllBytes(this.FileLocation));
}
public string FileLocation { get; private set; }
public MemoryStream Data
{
get
{
if (_cache == null)
_cache = new WeakReference(GetStream(), false);
var ret = _cache.Target as MemoryStream;
if (ret == null)
{
Recreated++;
ret = GetStream();
_cache.Target = ret;
}
return ret;
}
}
public int Recreated { get; private set; }
}
class Program
{
static void Main(string[] args)
{
var cache = CacheStore<string, FileCache>.Instance;
var fileName = @"c:\boot.ini";
cache[fileName] = new FileCache(fileName);
var ret = cache[fileName].Data.ToArray();
Console.WriteLine("Recreated {0}", cache[fileName].Recreated);
Console.WriteLine(Encoding.ASCII.GetString(ret));
GC.Collect();
var ret2 = cache[fileName].Data.ToArray();
Console.WriteLine("Recreated {0}", cache[fileName].Recreated);
Console.WriteLine(Encoding.ASCII.GetString(ret2));
GC.Collect();
var ret3 = cache[fileName].Data.ToArray();
Console.WriteLine("Recreated {0}", cache[fileName].Recreated);
Console.WriteLine(Encoding.ASCII.GetString(ret3));
Console.Read();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.