dotnet / dotnet/runtime

TimeZoneInfo.GetSystemTimeZones() allocates 8MB on the GC heap (linux-x64)

Open
#132,620 2 comments 0 reactions 0 assignees View on GitHub
area-System.DateTime tenet-performance
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

_From OrchardCMS's gc dump._

```cs
long before = GC.GetAllocatedBytesForCurrentThread();
var zones = TimeZoneInfo.GetSystemTimeZones();
long after = GC.GetAllocatedBytesForCurrentThread();
Console.WriteLine(after - before);
```
outputs: `8 373 656`. Seems like a lot. (same code on Windows is 0.6Mb).

On Ubuntu,  GetSystemTimeZones()  roughly does this:

1. Enumerates roughly 500 IANA zones.
2. Reads every corresponding TZif file.
3. Allocates temporary parsing buffers: transition dates, type indexes, offset records, abbreviations, and lists.
4. Eagerly converts every historical transition interval into a  TimeZoneInfo.AdjustmentRule .
5. Builds the zone dictionary, result array, names, and read-only collection.
6. Because this is the default overload, populates display names and sorts by  DisplayName .

The dump showed the dominant retained part:

• 498  TimeZoneInfo  objects
• 32,310  AdjustmentRule  objects: 3,360,240 bytes
• Their arrays: another 269,520 bytes
• 99.53% are Linux-style rules representing a single historical offset interval
• All are permanently retained in the global  TimeZoneInfo  cache

The remaining portion of the 8.37 MB includes temporary TZif parsing data, strings, dictionaries, sorting, and other supporting objects.  GetAllocatedBytesForCurrentThread()  measures everything allocated during the call, including objects that later die. Subsequent calls reuse the global cache and should allocate essentially nothing.

Possible optimizations:

- Keep TZif transitions in compact arrays and materialize `AdjustmentRule[]` only when `GetAdjustmentRules()` is called.
- Lazily parse historical transitions and initialize per-zone transition caches only when conversions need them.
- Share immutable transition data between aliases or equivalent zones.

Contributor guide

Open the contributing guide

Research direction

Start with the supplied C# allocation snippet on Ubuntu and inspect the GetSystemTimeZones() path, especially the global cache and AdjustmentRule creation described in the report. Done should be demonstrated by lower first-call allocation and retained memory using the supplied measurement, while subsequent calls still reuse the cache.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, linux
Domain
performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.