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();
}
}
그냥 명확히하기 위해, 당신은에서 OutOfMemory 예외를 얻을 수 없다 * 단지 * 가비지 컬렉터가 잡았되지 않았기 때문에 - 오해 이런 종류의 잘못을 뿌리는 사람에 이르게'GC.Collect를()'생각 자신의 코드 . 일부 메모리를 할당하라는 요청이 있고 충분하지 않은 경우 GC는 3 세대 모두 호출됩니다. 그러나 MemoryStream이 메모리를 모두 해제하기 위해서는 Dispose() (아마도'using()'을 통해)를 호출해야한다고 동의합니다. –
Dispose 메모리를 해제하지 마십시오. GC만이 그렇게 할 수 있습니다. – adrianm