TimeZoneInfo.GetSystemTimeZones() allocates 8MB on the GC heap (linux-x64)
- 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
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