-
Notifications
You must be signed in to change notification settings - Fork 868
Description
Description
We've noticed huge memory traffic in our app after we started to send larger attachments with SES, so I've composed small app to see what is going on. To send ~5MB email message SES SDK allocates > 250MB of memory, which is 50 times more than message itself, to send 4 such messages in parallel we need to allocate more than 1GB of RAM, which in my opinion is not right.
Screenshots are taken from dotMemory profiler, I was running console app below with allocations recording.
In total sending email allocated:
The call tree is very deep, hence did not fit in single screenshot, but main parts are two, CreateWebRequest:
and signing:
Some strange things, I have to admit that I haven't checked the source code:
- Seems that GetParametersAsString was called twice, hence allocating twice.
- Why you need to sign request - I'm pretty sure it travels through HTTPS.
- Why you need to encode everything as url and why it takes so much memory.
Reproduction Steps
Project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.SimpleEmail" Version="3.7.0.73" />
<PackageReference Include="MimeKit" Version="2.15.1" />
</ItemGroup>
</Project>
Program.cs
using System;
using System.IO;
using System.Threading.Tasks;
using Amazon;
using Amazon.Runtime;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using MimeKit;
namespace SesMemory
{
class Program
{
static async Task Main(string[] args)
{
var options = FormatOptions.Default.Clone();
var sesKey = "my-ses-key";
var sesSecret = "my-ses-secret";
var region = "us-west-2";
var amazonSimpleEmailService = new AmazonSimpleEmailServiceClient(
new BasicAWSCredentials(sesKey, sesSecret),
RegionEndpoint.GetBySystemName(region));
var mimeMessage = CreateMimeMessage();
// entry point for memory profiler capture
Console.WriteLine("press key to start");
Console.ReadKey();
using (var memoryStream = new MemoryStream())
{
await mimeMessage.WriteToAsync(options, memoryStream);
var sendRequest = new SendRawEmailRequest { RawMessage = new RawMessage(memoryStream)};
var response = await amazonSimpleEmailService.SendRawEmailAsync(sendRequest);
}
// exit point for memory profiler capture
Console.WriteLine("press key to exit");
Console.ReadKey();
}
private static MimeMessage CreateMimeMessage()
{
var emailMessage = new MimeMessage();
emailMessage.From.Add(new MailboxAddress("[email protected]", "[email protected]"));
emailMessage.To.Add(new MailboxAddress(string.Empty, "[email protected]"));
emailMessage.Subject = "test subject";
var emailBody = new BodyBuilder
{
TextBody = "text body",
HtmlBody = "html body"
};
// ~5mb png
emailBody.Attachments.Add("test.jpg", File.ReadAllBytes(@"C:\temp\test-image.png"));
emailMessage.Body = emailBody.ToMessageBody();
return emailMessage;
}
}
}
Environment
- SDK Version: 3.7.0.73
- Package Version: 3.7.0.73
- OS Info: Windows 10 | Linux Alpine
- Build Environment: Rider
- Targeted .NET Platform: 5.0
Resolution
Optimize memory allocations so that it would not be 50 times size of the message.
This is a 🐛 bug-report