我有一个在自己的应用程序池(IIS 8)中运行的网站。池的设置是默认设置,即每29小时回收一次。
我们的网络服务器只有8GB内存,我注意到这个网站的工作进程经常爬到6GB内存并使服务器慢慢爬行。这是当前Web服务器上唯一的站点。
我也安装了SQL Express 2016。该网站使用的是EF版本6.1.3。
MVC网站非常简单。它有一个GETPDF控制器,它在表中找到一行,获取存储在字段中的PDF信息,然后按如下方式将其提供给浏览器: -
using (eBillingEntities db = new eBillingEntities())
{
try
{
string id = model.id;
string emailaddress = Server.HtmlEncode(model.EmailAddress).ToLower().Trim();
eBillData ebill = db.eBillDatas.ToList<eBillData>().Where(e => e.PURL == id && e.EmailAddress.ToLower().Trim() == emailaddress).FirstOrDefault<eBillData>();
if (ebill != null)
{
// update the 'Lastdownloaded' field.
ebill.LastDownloaded = DateTime.Now;
db.eBillDatas.Attach(ebill);
var entry = db.Entry(ebill);
entry.Property(en => en.LastDownloaded).IsModified = true;
db.SaveChanges();
// Find out from the config record whether the bill is stored in the table or in the local pdf folder.
//
Config cfg = db.Configs.ToList<Config>().Where(c => c.Account == ebill.Account).FirstOrDefault<Config>();
bool storePDFDataInEBillTable = true;
if (cfg != null)
{
storePDFDataInEBillTable = cfg.StorePDFDataInEBillDataTable;
}
// End of Modification
byte[] file;
if (storePDFDataInEBillTable)
{
file = ebill.PDFData;
}
else
{
string pathToFile = "";
if (string.IsNullOrEmpty(cfg.LocalPDFDataFolder))
pathToFile = cfg.LocalBackupFolder;
else
pathToFile = cfg.LocalPDFDataFolder;
if (!pathToFile.EndsWith(@"\"))
pathToFile += @"\";
pathToFile += ebill.PDFFileName;
file = System.IO.File.ReadAllBytes(pathToFile);
}
MemoryStream output = new MemoryStream();
output.Write(file, 0, file.Length);
output.Position = 0;
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=ebill.pdf");
return new FileStreamResult(output, "application/pdf");
}
else
return View("PDFNotFound");
}
catch
{
return View("PDFNotFound");
}
这里有没有内存泄漏?
文件字节数组和内存流是否会被释放?
另外,关于清理实体框架引用,还有什么需要做的吗?
如果代码看起来不错,哪里开始寻找好的地方?
此致
答案 0 :(得分:0)
这里有没有内存泄漏?
没有
文件字节数组和内存流是否会被释放?
最终,是的。但这可能是你过度记忆的原因。
另外,关于清理实体框架引用,还有什么需要做的吗?
没有
如果代码看起来不错,哪里开始寻找好的地方?
如果此代码是高内存使用的原因,那么因为您正在将文件加载到内存中。并且你要在内存中加载每个文件的两个副本,一个在byte []中并复制到MemoryStream。
没有必要这样做。
要消除文件的第二个副本,请使用MemoryStream(byte[])构造函数,而不是将字节[]中的字节复制到空的MemoryStream。
要消除内存中的第一个副本,您可以将数据流式传输到将成为FileStreamResult目标的临时文件中,或使用ADO.NET流初始化FileStreamResult。
请参阅https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sqlclient-streaming-support
如果您转到ADO.NET流式传输DbContext,则需要将其范围限定为Controller,而不是局部变量,这在任何情况下都是一种很好的做法。
答案 1 :(得分:0)
除了大卫的建议。我注意到我正在做以下
**db.eBillDatas.ToList<eBillData>()**
因此我从数据库中获取了所有数据然后再次使用where子句获取数据。
在数据库开始填满之前,我没有注意到这个问题。
我删除了那部分,现在IIS工作者处理大约是100mb。