We use machine learning technology to do auto-translation. Click "English" on top navigation bar to check Chinese version.
Configuring .NET Garbage Collection for Amazon ECS and Amazon Web Services Lambda
.NET developers rely on .NET’s automatic memory allocation and garbage collection (GC) mechanisms to handle the memory needs of their applications. For most use cases GC isn’t something developers need to worry about. However, in modern architectures where .NET applications are running in memory constrained environments, like containers and
Amazon Elastic Container Service (ECS)
.NET container applications are deployed to ECS as an
A hierarchy of cgroups for the task and the individual containers in the task are created when launching a ECS Task. The task’s memory settings are configured for the parent cgroup, which limits the amount of memory for the child cgroups used for the containers. However, the .NET GC does not support traversing the cgroup hierarchy for determining the amount of available memory. This means if memory is only configured at the task definition level the .NET GC doesn’t see the cgroup’s memory restriction, and instead detects the size of the underlying host compute’s memory.
To illustrate, running the following application will report the available memory the .NET GC sees is available. If you deploy this as an ECS Task using Fargate with the minimum memory setting of 0.5GB, the application will report there is 4GB available. The 4GB is coming from the underlying host compute.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Memory Test");
app.MapGet("/memory", () =>
{
return GC.GetGCMemoryInfo().TotalAvailableMemoryBytes.ToString("N0");
});
app.Run();
This causes the .NET GC to not aggressively release unused memory in the heap when it detects the .NET process is getting near the 0.5GB limit configured for the ECS task. This can trigger an OutOfMemoryException and shut down the container.
If a hard memory limit is set on the container definition within the ECS Task definition, the cgroup for the container will have a memory limit set and the .NET GC will see the correct amount of available memory for it to manage. You can set the hard memory limit in the console for the Task definition in the Environment section. This container hard memory limit can also be set programmatically through the Amazon Web Services SDKs,
Once the new task definition is deployed to ECS the example code above will now report, correctly, that there is 0.5GB of available memory for the GC.
If the task definition has multiple containers defined then you will need to divide up the task definition’s allocated memory as needed across the different containers.
Amazon Web Services .NET Deploy Tools
In the latest versions of the
Amazon Web Services Lambda
.NET code in Lambda also runs in a memory constrained environment. The minimum memory size for a Lambda function is 128 MB. Like Fargate, Lambda uses Linux’s cgroups to restrict CPU and memory settings based on the Lambda function’s configured memory size. However, in the case of Lambda the use of cgroups is completely hidden from the .NET runtime. This again, causes the .NET GC to think that more memory is available than is really the case.
For example, if you deploy the following function with a memory size of 128MB it will likely report a memory size larger then 128MB.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace LambdaMemoryCheck;
public class Function
{
public string FunctionHandler()
{
return GC.GetGCMemoryInfo().TotalAvailableMemoryBytes.ToString("N0");
}
}
Lambda, unlike ECS, does not have a container hard memory limit you can set. To inform the .NET GC how much memory is available you can set the DOTNET_GCHeapHardLimit environment variable that the .NET GC knows to look for. The value of DOTNET_GCHeapHardLimit is the number of bytes in hexadecimal the GC should limit itself too. For convenience the table below gives the hexadecimal values for the available Lambda configurations up to 1GB.
Lambda | hexadecimal |
---|---|
128MB | 0x8000000 |
192MB | 0xC000000 |
256MB | 0x10000000 |
320MB | 0x14000000 |
384MB | 0x18000000 |
448MB | 0x1C000000 |
512MB | 0x20000000 |
576MB | 0x24000000 |
640MB | 0x28000000 |
704MB | 0x2C000000 |
768MB | 0x30000000 |
832MB | 0x34000000 |
896MB | 0x38000000 |
960MB | 0x3C000000 |
1024MB | 0x40000000 |
The DOTNET_GCHeapHardLimit environment variable can be set programmatically using any of the Amazon Web Services SDKs and tools. It can also be set in the Amazon Web Services Console, and in Visual Studio using the
Conclusion
If your .NET applications are experiencing memory issues we recommend tweaking the GC with container hard memory limits or using the DOTNET_GCHeapHardLimit environment variable for Lambda functions. For more information on configuration settings for the .NET GC checkout this
In the future, Amazon Web Services and Microsoft hope to make the .NET GC automatically understand the memory restrictions in these environments. Microsoft has opened a
Special thanks to
The mentioned AWS GenAI Services service names relating to generative AI are only available or previewed in the Global Regions. Amazon Web Services China promotes AWS GenAI Services relating to generative AI solely for China-to-global business purposes and/or advanced technology introduction.