检查C#中的可用内存分配

时间:2010-03-22 02:20:39

标签: c# .net memory-management

我需要在我的应用程序中创建一个函数来设置其可用的内存使用量。我想要做的是当应用程序运行时,它达到设置的内存设置,我将不得不从保存切换到内存到保存到本地驱动器的文件,以避免应用程序挂起。这是一个更好的方法吗?在内存分配方面做什么事情需要考虑?希望你理解:)

谢谢,

Jepe

3 个答案:

答案 0 :(得分: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();
  }
}

答案 1 :(得分:1)

您不需要这样做:让操作系统自动处理它,它会随着时间的推移而进行多年的性能调整和改进,并且通常会做很多工作。

对于更长的解释,read this来自Varnish网络代理的制造商。

答案 2 :(得分:0)

您可能需要考虑为此应用程序使用memory mapped file

如果将数据写入内存映射文件,则可以根据需要通过自动分页获得内存访问大部分数据的好处。