有没有办法限制允许 C# 方法分配的最大内存?我们正在处理复杂的用户提供的输入,我们意识到可以通过提供某种特殊输入来拒绝我们的服务。我们无法检测到 DoS 攻击的所有变体,因此我们希望限制 ProcessInput()
方法的处理时间和内存分配。
处理时间很“简单”,我们只需运行一个计时器并通过 CancellationToken 取消 ProcessInput 操作。但是,我们还没有找到内存分配的(简单)解决方案。我们不想编写自己的内存管理器并使用对象数组或类似的东西。
最佳答案
GC 堆是按进程分配的,而不是按 AppDomain 分配的 - 因此为了正确估计,您需要生成一个单独的进程。
您甚至可以自己托管 CLR 来影响段大小并获取通知。但是,如果该过程中没有其他任何东西在运行并且您对估计没有问题,那么 GC.GetTotalMemory()。但是,如果您对“方法运行期间消耗的总内存”而不是“在任何时间点使用的最大总内存”感兴趣,则需要在“NoGC”区域中执行 - 因为 GC 可以在期间触发多次你的方法运行。
为了限制生成进程对性能/资源的影响,您可以生成 N 个进程(其中 N 是您所需的并发级别),然后让每个进程从中央进程的工作窃取队列中提取任务,而子进程同步处理请求。
一个糟糕的想法(你需要处理结果报告以及 100 个其他“次要”事情):
主要流程:
public void EnqueueWork(WorkRequest request)
{
_workQueue.Enqueue(request);
}
ConcurrentQueue<WorkRequest> _workQueue = new ConcurrentQueue<WorkRequest>();
[OperationContract]
public bool GetWork(out WorkRequest work)
{
return _workQueue.TryDequeue(out work);
}
工作进程:
public void ProcessRequests()
{
WorkRequest work;
if (GetWork(out work))
{
try
{
//this actually preallocates 2 * _MAX_MEMORY - for ephemeral segment and LOH
// it also performs full GC collect if needed - so you don't need to call it yourself
if (!GC.TryStartNoGCRegion(_MAX_MEMORY))
{
//fail
}
CancellationTokenSource cts = new CancellationTokenSource(_MAX_PROCESSING_SPAN);
long initialMemory = GC.GetTotalMemory(false);
Task memoryWatchDog = Task.Factory.StartNew(() =>
{
while (!cts.Token.WaitHandle.WaitOne(_MEMORY_CHECK_INTERVAL))
{
if (GC.GetTotalMemory(false) - initialMemory > _MAX_MEMORY)
{
cts.Cancel();
//and error out?
}
}
})
DoProcessWork(work, cts);
cts.Cancel();
GC.EndNoGCRegion();
}
catch (Exception e)
{
//request failed
}
}
else
{
//Wait on signal from main process
}
}
关于c# - 限制 C# 方法的最大内存使用量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46463758/