有没有办法限制允许C#方法分配的最大内存?我们正在处理复杂的用户提供的输入,我们意识到可以通过提供一定的特殊输入来帮助我们的服务。我们无法检测到DoS攻击的所有变化,因此我们希望限制ProcessInput()
方法的处理时间和内存分配。
处理时间“简单”,我们只需运行一个计时器并通过CancellationToken取消ProcessInput操作。但是,我们还没有找到(简单)内存分配的解决方案。我们不想编写自己的内存管理器并使用对象数组或类似的东西。
答案 0 :(得分:1)
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
}
}