2010-03-22 62 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