性能是优化出来的,不管是在上生产前,还是在上生产后。大部分性能在性能测试阶段就能发现问题,但也有一些性能问题,结合生产的环境,生产数据才能表现出来,成为一个显著的瓶颈。
这次是生成pdf造成的内存泄露,大体代码如下,具体表现是内存缓慢增长,在docker中比windows增长速度要快,但都有只增不回收的特点。
using System.Data;
using System.Reflection.Metadata;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using QuestPDF.Fluent;
using QRCoder;
using Microsoft.AspNetCore.Mvc;
using QuestPDF.Drawing;
using QuestPDF;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/getpdf", () =>
{
var table = new DataTable();
for (var i = 0; i < 10; i++)
{
table.Columns.Add(i.ToString());
}
for (var row = 0; row < 1000; row++)
{
table.Rows.Add(row.ToString(), row.ToString(), row.ToString(), row.ToString(), row.ToString(), row.ToString(), row.ToString(), DateTime.Now + "wwewrwerewfdsfdswefwefewfwefwefew" + row, row.ToString(), row.ToString());
}
return TypedResults.File(GetPDF(table), contentType: "application/pdf", fileDownloadName: "a.pdf");
});
app.Run();
static IContainer CellStyle(IContainer container)
{
return container.DefaultTextStyle(x => x.SemiBold().FontSize(11)).PaddingVertical(5).BorderBottom(1).BorderColor(Colors.Black);
}
static byte[] GetPDF(DataTable dt)
{
var doc = QuestPDF.Fluent.Document.Create(container =>
{
using var stream = File.OpenRead(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "fonts", "MEIRYO.TTC"));
FontManager.RegisterFont(stream);
Settings.EnableCaching = true;
Settings.EnableDebugging = false;
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(14).FontFamily("Meiryo"));
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(x =>
{
x.Item().Table(table =>
{
table.ColumnsDefinition(columns =>
{
for (var i = 0; i < dt.Columns.Count; i++)
{
columns.RelativeColumn();
}
});
table.Header(header =>
{
foreach (DataColumn col in dt.Columns)
{
header.Cell().Element(CellStyle).Text(col.ColumnName);
}
});
foreach (DataRow row in dt.Rows)
{
for (var i = 0; i < dt.Columns.Count; i++)
{
if (i == 7)
{
byte[] qrCodeAsBitmapByteArr = PngByteQRCodeHelper.GetQRCode(row[i].ToString(), QRCodeGenerator.ECCLevel.Q, 20, false);
using var ms = new MemoryStream(qrCodeAsBitmapByteArr);
table.Cell().Image(qrCodeAsBitmapByteArr);
}
else
{
table.Cell().Element(CellStyle).Text(row[i].ToString());
}
}
}
});
});
page.Footer()
.AlignCenter()
.Text(x =>
{
x.Span("Page ");
x.CurrentPageNumber();
x.Span("/ ");
x.TotalPages();
});
});
});
return doc.GeneratePdf();
}
各种.net的调试工具用上,都只能证明内存只增不减,连pmap都用上了,发现下面的一个大文件的内存占用,并且很多,大体都是在65M左右。
Address Kbytes RSS Dirty Mode Mapping
00007f4d54000000 65536 65536 65536 rw--- [ anon ]
经过一天的测试,找不到具体的问,最后推测是生成Pdf后,生成的内存是非托管内存,GC回收不掉,每当有用户下载PDF时,就会积累内存,直到Pod崩掉。