Exploring DATAS
04/20/2024
4 minutes
.NET 8 introduced a new garbage collection feature: Dynamic Adaptation To Application Sizes or DATAS. The inner workings of it are detailed in this post.
This feature tunes the GC to adjust the number of heaps and execute compacting garbage collections more often to have a smaller overall heap size. The result should be a heap size that more closely resembles the actual amount of memory that the application uses.
This feature is great for memory constrained environments or with uneven loads, where memory may be reclaimed between the loads.
In this post I will enable DATAS on my test server application and test client side application to observe the differences in the memory utilization.
My test machine has a 12 CPU, which means with Server GC the default number of heaps is 12. I use PerfView and capture and compare sessions of the server and client applications. The CHttp client application is configured to send 2000 requests in total from 30 threads. The test web application has an endpoint that returns 100 000 items of string
s with each of a unique string
object 234 + MT + syncblock in bytes. The captured sessions are about ~25 seconds long. While the test application is really a sample application without more involved business logic or data access, the client app runs in production with processing real workloads.
I captured multiple sessions. The tables below show the median result values.
Server App
An ASP.NET Core webapi application is targeting .NET 8 with Server GC mode. Server GC can be disabled by setting ServerGarbageCollection
to false. However, there is not much benefit setting for DATAS, as DATAS can only be enabled with Server GC mode.
Metric | Workstation GC | Server GC | Server GC + DATAS |
---|---|---|---|
Heap Count | 1 | 12 | 11 |
% Pause GC | 36,8% | 4,6% | 14,0% |
Max Heap Size | 14,866 MB | 108,230 MB | 35,507 MB |
# of GC runs | 8465 | 589 | 1966 |
In this test application my measurements position DATAS mode between the Workstation GC and the Server GC mode. The heap count stands closer to a Server GC as my tests mostly conclude a bursty load excluding cooldown, so without capturing the time for the GC to scale down. The remaining metrics seem to suggest a nice balance of significantly reduced heap size (max heap size reduced by 68%), while the GC pause time increased from 1.003,3 msec (Server GC) to 3.187,3 msec (DATAS). Where memory is more constrained, and performance is not as critical (ie. dev or test environments cluttered with containers) the DATAS mode could bring real benefits compared to the regular Server GC mode.
Client App
The CHttp application at the time of writing this post runs on .NET 8 with Workstation GC mode as the dotnet tool (Publish AOT mode as the VS Code plugin.
I compared the same three use-cases as above for the server application.
Metric | Workstation GC | Server GC | Server GC + DATAS |
---|---|---|---|
Heap Count | 1 | 12 | 1 |
% Pause GC | 24,7% | 2,2% | 7,0% |
Max Heap Size | 62,506 MB | 255,075 MB | 262,800 MB |
# of GC runs | 1153 | 47 | 401 |
Compared to the Workstation GC mode, the Server GC manages significantly fewer GC runs at the expense of a larger heap size. As before Server GC with DATAS is positioned between, however the benefits are not as obvious. In this case the heap count remained one, more similar to the Workstation mode. However, the Max Heap Size as well as the % Pause GC is even larger to the values observed for the standalone Server GC mode. Running this application in Server GC + DATAS is less attractive compared to running it simply in Server GC mode.
Given this is a typically a short-lived application sending many requests and awaiting responses before generating a report and exiting, it might not be worth spending significant amount of CPU cycles on GC. Users of this app are expected to use it in an environment where other workloads do not interfere with the system. With that in mind, enabling the Server GC for this application seems reasonable.
Conclusion
DATAS may be enabled for Server GC mode. To enable DATAS, set GarbageCollectionAdaptationMode
with value 1. This mode can make sense for applications that are less performance critical, but more memory constrained. In DATAS mode the GC runs more frequently that can significantly reduce the heap size by reclaiming more garbage.
However, DATAS mode will behave differently in each application, hosting environment (test/qa/prod) as well as load. There is no clear rule of thumb on which GC mode to use, other than carefully measuring and analyzing each use-case.