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

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

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();
  }
}

你说得对:),你有关于你所说的内容的示例代码吗?我在内存和文件流方面是个新手.. 我真的很需要它。 - Jepe d Hepe
你的意思是创建一个流,它可以从内存流切换到文件流吗? - MaxGuernseyIII
是的,但是能否将一个类放入MemoryStream然后写入文件呢?我的应用程序会在一段时间内填充该类。随着时间的推移,它的大小增加,我认为这会导致我的应用程序进程变慢,有时甚至会挂起。 - Jepe d Hepe

1
你不需要这样做:让操作系统自动处理它,它已经经过多年的性能调整和改进,通常会做得更好。
更详细的解释,请阅读此文章,由Varnish Web代理的制造商提供。

1
如果他创建了大量的对象,那么就会触发垃圾回收。听起来他试图避免触发GC。 - Gabe

0
你可能想考虑在这个应用程序中使用内存映射文件
如果你把数据写入内存映射文件,你就可以享受到许多数据的内存访问和自动分页的好处。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接