2010-03-22 66 views
3

我需要在應用程序中創建一個函數來設置其可用內存使用情況。我想要做的是當應用程序正在運行時,它會達到設置的內存設置,我將不得不從保存到內存切換到保存到本地驅動器的文件以避免應用程序掛起。這是更好的方法嗎?在內存分配方面做這件事需要考慮什麼?希望你能理解:)檢查C#中的可用內存分配情況

感謝,

Jepe

回答

3

您可以通過System.Diagnostics.Process或性能計數器獲得粗略估計值。但是,您可能應該重新考慮這種方法,因爲您可能有更好的方法來判斷是應該寫入內存還是寫入磁盤。

首先,這可能不是總內存使用率問題。這個問題聽起來像是生活在少數甚至是一個地方。我會考慮通過考慮你的需求來使這件事變得更聰明。然後我會用設計來解決這個問題。

也許你需要保存到磁盤每次,但使用緩存代理(使讀取來自內存)。也許你需要一個System.IO.Stream的實現,該實現代表具有預定容量的MemoryStream,直到它接近該容量,然後切換到FileStream。也許就像使用排隊來計量你的系統某個部分的負載一樣簡單,這樣內存永遠不會成爲問題。

不知道更多關於您的具體問題,很難準確地告訴您應該做什麼。我只能說,基於內存使用情況的預測行爲將導致一些冒險行爲難以測試,因此難以維護。

這是我的兩分錢,我想。


編輯:

添加請求的類。這並沒有完成TDD,但給你一個解決這個問題的方法。

class UpgradingStream : Stream 
{ 
    // state pattern lives in the problem... 
    private abstract class InternalState 
    { 
    private readonly Stream _underlyingStream; 

    protected InternalState(Stream underlyingStream) 
    { 
     _underlyingStream = underlyingStream; 
    } 

    internal Stream GetUnderlyingStream() 
    { 
     return _underlyingStream; 
    } 

    // template method lives in the implementation of this state pattern 
    internal InternalState Seek(long offset, SeekOrigin origin, out long result) 
    { 
     result = _underlyingStream.Seek(offset, origin); 

     return GetNextState(); 
    } 

    internal InternalState SetPosition(long value) 
    { 
     _underlyingStream.Position = value; 

     return GetNextState(); 
    } 

    internal InternalState SetLength(long value) 
    { 
     _underlyingStream.SetLength(value); 

     return GetNextState(); 
    } 

    internal InternalState Write(byte[] buffer, int offset, int count) 
    { 
     _underlyingStream.Write(buffer, offset, count); 

     return GetNextState(); 
    } 

    protected abstract InternalState GetNextState(); 
    } 

    private class InMemoryOnly : InternalState 
    { 
    private readonly Func<Stream> _getUpgradedStream; 
    private readonly int _threshold; 

    private InMemoryOnly(int threshold, Func<Stream> getUpgradedStream) 
     : base(new MemoryStream(threshold)) 
    { 
     _threshold = threshold; 
     _getUpgradedStream = getUpgradedStream; 
    } 

    internal static InternalState GetInstance(int threshold, Func<Stream> getUpgradedStream) 
    { 
     return new InMemoryOnly(threshold, getUpgradedStream); 
    } 

    protected override InternalState GetNextState() 
    { 
     if (GetUnderlyingStream().Length > _threshold) 
     { 
     var newStream = _getUpgradedStream(); 

     CopyStream(newStream); 

     return Unrestricted.GetInstance(newStream); 
     } 

     return this; 
    } 

    private void CopyStream(Stream newStream) 
    { 
     var originalPosition = GetUnderlyingStream().Position; 

     GetUnderlyingStream().Position = 0; 

     int bytesRead; 

     var buffer = new byte[65536]; 

     while ((bytesRead = GetUnderlyingStream().Read(buffer, 0, buffer.Length)) != 0) 
     { 
     newStream.Write(buffer, 0, bytesRead); 
     } 

     newStream.Position = originalPosition; 
    } 
    } 

    private class Unrestricted : InternalState 
    { 
    private Unrestricted(Stream underlyingStream) 
     : base(underlyingStream) 
    { 
    } 

    internal static Unrestricted GetInstance(Stream stream) 
    { 
     return new Unrestricted(stream); 
    } 

    protected override InternalState GetNextState() 
    { 
     // state never changes once we are in a file or whatever 
     return this; 
    } 
    } 

    private InternalState _state; 

    private UpgradingStream(int threshold, Func<Stream> getMoreEfficientStream) 
    { 
    _state = InMemoryOnly.GetInstance(threshold, getMoreEfficientStream); 
    } 

    internal static Stream GetInstance(int threshold, Func<Stream> getMoreEfficientStream) 
    { 
    return new UpgradingStream(threshold, getMoreEfficientStream); 
    } 

    public override bool CanRead 
    { 
    get { return _state.GetUnderlyingStream().CanRead; } 
    } 

    public override bool CanSeek 
    { 
    get { return _state.GetUnderlyingStream().CanSeek; } 
    } 

    public override bool CanWrite 
    { 
    get { return _state.GetUnderlyingStream().CanWrite; } 
    } 

    public override void Flush() 
    { 
    _state.GetUnderlyingStream().Flush(); 
    } 

    public override long Length 
    { 
    get { return _state.GetUnderlyingStream().Length; } 
    } 

    public override long Position 
    { 
    get 
    { 
     return _state.GetUnderlyingStream().Position; 
    } 
    set 
    { 
     _state = _state.SetPosition(value); 
    } 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
    return _state.GetUnderlyingStream().Read(buffer, offset, count); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    { 
    long result; 

    _state = _state.Seek(offset, origin, out result); 

    return result; 
    } 

    public override void SetLength(long value) 
    { 
    _state = _state.SetLength(value); 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
    _state = _state.Write(buffer, offset, count); 
    } 

    public override void Close() 
    { 
    _state.GetUnderlyingStream().Close(); 
    } 
} 
+0

youre right :),你有什麼樣的代碼,你說什麼?我是內存和文件流的新手interms ..我有點急需它。 – 2010-03-22 06:06:44

+0

你的意思是說有一個從內存流切換到文件流的流? – 2010-03-22 07:26:40

+0

是的..但是有可能把一個類放入一個內存流然後文件? :)我的應用程序填充該類一段時間。隨着時間的推移,它的大小會增加,我認爲,這會導致我的應用程序中的進程變慢,有時會掛斷。 – 2010-03-22 07:29:38

0

你可能要考慮使用memory mapped file這種應用。

如果您將數據寫入內存映射文件,您可以根據需要使用自動分頁功能獲得內存訪問大部分數據的好處。

1

你不需要這樣做:讓操作系統自動處理它,它有多年的性能調整和改進,隨着時間的推移會增加,通常會做很多工作。

對於較長的解釋,read this來自Varnish Web代理的製造商。

+1

如果他創建了很多對象,它將觸發垃圾回收。這聽起來像他試圖避免觸發GC。 – Gabe 2010-03-22 02:33:35