为什么asp.net web服务占用这么多内存?

为什么asp.net web服务占用这么多内存?,asp.net,.net,iis,memory,Asp.net,.net,Iis,Memory,我有一个.NETWeb服务(WebAPI2),它接受从数据库获取数据的请求。返回的数据不是很大,通常只有1-3KB(数据库中大约有1-15行)。我在IIS中设置了它,并对它进行了一些批量测试,在一个小时左右的时间里,它受到了很多攻击,因此它收到了数千个请求。当我查看w3wp.exe(IIS工作进程)时,内存一直在增加,直到超过5GB,CPU使用率接近100%,然后最终web服务停止工作。服务器有16 gb的RAM,我们刚刚将其从8增加到了16 gb。5GB内存正常吗?这似乎太多了,我本以为垃圾收

我有一个.NETWeb服务(WebAPI2),它接受从数据库获取数据的请求。返回的数据不是很大,通常只有1-3KB(数据库中大约有1-15行)。我在IIS中设置了它,并对它进行了一些批量测试,在一个小时左右的时间里,它受到了很多攻击,因此它收到了数千个请求。当我查看w3wp.exe(IIS工作进程)时,内存一直在增加,直到超过5GB,CPU使用率接近100%,然后最终web服务停止工作。服务器有16 gb的RAM,我们刚刚将其从8增加到了16 gb。5GB内存正常吗?这似乎太多了,我本以为垃圾收集会更好地处理这个问题。我在使用性能监视器或其他东西来解决此类问题方面不是很有经验

对我能看什么有什么建议吗?可能是内存泄漏吗?当应用程序池达到某个内存量时,我是否应该尝试让其循环使用

更新-我们有另一个.NETWeb服务,它甚至不访问数据库或任何外部文件或任何东西,而且它的行为方式相同-内存只是不断增加。我们的计划可能是将每个应用程序的应用程序池设置为每x分钟循环一次,或者当它达到某个内存量时循环一次

以下是API中典型函数的示例:

[Route("patient/{patientKey}/activations")]
public async Task<IHttpActionResult> GetActivations(int patientKey)
{
     try
     {
          ActivationList actList = new ActivationList();

          actList.Activations = await _actProc.GetByPatient(patientKey);

          return Ok<ActivationList>(actList);
     }
     catch (Exception ex)
     {
         return new BadRequestWithInfoResult(Translators.makeXML<ErrorReturn>(CreateError(ex)));
     }
}

public async Task<List<Activation>> GetByPatient(long patientKey)
{
     using (var dbConn = _database.CreateConnection())
     {
          List<DBActivation> lst_Activation = await dbConn.FetchAsync<DBActivation>("select * from fact.Activation where PatientKey = " + patientKey.ToString());

          List<Activation> Activations = lst_Activation.Select(x => _mapper.Map<Activation>(x)).ToList<Activation>();              

          return Activations;
     }
}
[路径(“患者/{patientKey}/激活”)]
公共异步任务GetActivations(int patientKey)
{
尝试
{
ActivationList actList=新的ActivationList();
actList.Activations=Wait _actProc.GetByPatient(patientKey);
返回Ok(actList);
}
捕获(例外情况除外)
{
返回新的BadRequestWithInfoResult(Translators.makeXML(CreateError(ex));
}
}
公共异步任务GetByPatient(长patientKey)
{
使用(var dbConn=\u database.CreateConnection())
{
List lst_Activation=wait dbConn.FetchAsync(“select*from fact.Activation where PatientKey=“+PatientKey.ToString());
List Activations=lst_Activation.Select(x=>_mapper.Map(x)).ToList();
返回激活;
}
}

激活对象中有什么?如果激活有许多子项,在映射过程中,它可能会尝试填充所有子项以及子项的子项,等等。。。如果您正在使用EF延迟加载,EF将为每个子总体创建一个子查询。

由于未在库中使用ConfigureAwait,因此似乎出现了死锁

[Route("patient/{patientKey}/activations")]
public async Task<IHttpActionResult> GetActivations(int patientKey)
{
     try
     {
          ActivationList actList = new ActivationList();

          actList.Activations = await _actProc.GetByPatient(patientKey).ConfigureAwait(false);

          return Ok<ActivationList>(actList);
     }
     catch (Exception ex)
     {
         return new BadRequestWithInfoResult(Translators.makeXML<ErrorReturn>(CreateError(ex)));
     }
}

public async Task<List<Activation>> GetByPatient(long patientKey)
{
     using (var dbConn = _database.CreateConnection())
     {
          List<DBActivation> lst_Activation = await dbConn.FetchAsync<DBActivation>("select * from fact.Activation where PatientKey = " + patientKey.ToString()).ConfigureAwait(false);

          List<Activation> Activations = lst_Activation.Select(x => _mapper.Map<Activation>(x)).ToList<Activation>();              

          return Activations;
     }
}
[路径(“患者/{patientKey}/激活”)]
公共异步任务GetActivations(int patientKey)
{
尝试
{
ActivationList actList=新的ActivationList();
actList.Activations=await _actProc.GetByPatient(patientKey).ConfigureAwait(false);
返回Ok(actList);
}
捕获(例外情况除外)
{
返回新的BadRequestWithInfoResult(Translators.makeXML(CreateError(ex));
}
}
公共异步任务GetByPatient(长patientKey)
{
使用(var dbConn=\u database.CreateConnection())
{
List lst_Activation=await dbConn.FetchAsync(“从事实.激活中选择*,其中PatientKey=“+PatientKey.ToString())。ConfigureAwait(false);
List Activations=lst_Activation.Select(x=>_mapper.Map(x)).ToList();
返回激活;
}
}

OP answer-我发现了一些有问题的代码(不,像这样的web服务使用超过5 gb的内存是不正常的)。不久前,当我试图在web服务返回的xml中创建自己的名称空间时,我在@Konamiman的回答下添加了本文中指定的CustomNamespaceXmlFormatter类:下面的注释者提到了内存泄漏问题。虽然ANTS Memory Profiler从未显示我的web服务生成多个动态程序集,但我还是更新了代码,使用类似于单例模式的方式创建XmlSerializer实例,如下所示,现在我的内存使用已得到控制(在处理完请求后,内存使用量实际上会下降!)

公共类CustomNamespaceXmlFormatter:XmlMediaTypeFormatter
{
私有只读字符串defaultRootNamespace;
public CustomNamespaceXmlFormatter():此(string.Empty)
{
}
公共CustomNamespaceXmlFormatter(字符串defaultRootNamespace)
{
this.defaultRootNamespace=defaultRootNamespace;
}
公共重写任务WriteToStreamAsync(类型类型、对象值、流writeStream、HttpContent内容、TransportContext TransportContext)
{
if(type==typeof(String))
{
//如果我们只想返回一个字符串,只需将其作为值发送到输出
返回base.WriteToStreamAsync(类型、值、writeStream、内容、transportContext);
}
其他的
{
XmlRootAttribute XmlRootAttribute=(XmlRootAttribute)type.GetCustomAttributes(typeof(XmlRootAttribute),true)[0];
if(xmlRootAttribute==null)
xmlRootAttribute=新的xmlRootAttribute(type.Name)
{
Namespace=defaultRootNamespace
};
else if(xmlRootAttribute.Namespace==null)
xmlRootAttribute=新的xmlRootAttribute(xmlRootAttribute.ElementName)
{
Namespace=defaultRootNamespace
};
var xns=新的XmlSerializerNamespaces();
Add(string.Empty,xmlRootAttribute.Namespace);
返回Task.Factory.StartNew(()=>
{
//var serializer=新的XmlSerializer(类型,xmlRootAttribute);**旧代码**
var serializer=XmlSerializerInstance.GetSerializer(类型,xmlRootAttribute);
serializer.Serialize(writeStream,value,xns);
});
}
}
}
公共静态类XmlSerializerInstance
{
公共静态对象_lock=新对象();
公共静态字典\u序列化程序
public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter
{
    private readonly string defaultRootNamespace;

    public CustomNamespaceXmlFormatter() : this(string.Empty)
    {
    }

    public CustomNamespaceXmlFormatter(string defaultRootNamespace)
    {
        this.defaultRootNamespace = defaultRootNamespace;
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        if (type == typeof(String))
        {
            //If all we want to do is return a string, just send to output as <string>value</string>
            return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
        }
        else
        {
            XmlRootAttribute xmlRootAttribute = (XmlRootAttribute)type.GetCustomAttributes(typeof(XmlRootAttribute), true)[0];
            if (xmlRootAttribute == null)
                xmlRootAttribute = new XmlRootAttribute(type.Name)
                {
                    Namespace = defaultRootNamespace
                };
            else if (xmlRootAttribute.Namespace == null)
                xmlRootAttribute = new XmlRootAttribute(xmlRootAttribute.ElementName)
                {
                    Namespace = defaultRootNamespace
                };

            var xns = new XmlSerializerNamespaces();
            xns.Add(string.Empty, xmlRootAttribute.Namespace);

            return Task.Factory.StartNew(() =>
            {
                //var serializer = new XmlSerializer(type, xmlRootAttribute); **OLD CODE**
                var serializer = XmlSerializerInstance.GetSerializer(type, xmlRootAttribute);
                serializer.Serialize(writeStream, value, xns);                    
            });
        }
    }
}

public static class XmlSerializerInstance
{
    public static object _lock = new object();
    public static Dictionary<string, XmlSerializer> _serializers = new Dictionary<string, XmlSerializer>();
    public static XmlSerializer GetSerializer(Type type, XmlRootAttribute xra)
    {
        lock (_lock)
        {
            var key = $"{type}|{xra}";
            if (!_serializers.TryGetValue(key, out XmlSerializer serializer))
            {
                if (type != null && xra != null)
                {
                    serializer = new XmlSerializer(type, xra);
                }

                _serializers.Add(key, serializer);
            }

            return serializer;
        }
    }
}