SIGN IN SIGN UP

perf(core): SDK Overhead Reduction (#5499)

* collection: SDK Overhead Reduction

* perf(core): Skip java.specification.version lookup on Android

Android is never Java 9+, so the System.getProperty +
Double.valueOf parse in the Platform static initializer is
unnecessary overhead on the Android cold-start path.
Short-circuit to isJavaNinePlus=false when isAndroid is true.

* perf(android): Replace reflective OptionsContainer with direct subclass

Replace OptionsContainer.create(SentryAndroidOptions.class) which uses
getDeclaredConstructor().newInstance() with a direct
SentryAndroidOptionsContainer subclass that returns
new SentryAndroidOptions() without reflection.

Make OptionsContainer non-final (@Open) with a protected no-arg
constructor so Android can subclass it.

* collection: SDK Overhead reduction for JVM

* perf(core): Short-circuit combined scope breadcrumbs

Avoid allocating and sorting a merged breadcrumb queue when only one component scope has breadcrumbs. This keeps the full merge path for multi-scope breadcrumbs and returns the default write scope queue when all scopes are empty.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Reduce envelope writer buffer size

Use an explicit 512-character BufferedWriter buffer for envelope item and envelope serialization. This avoids allocating the oversized default char buffer for each short-lived serialization writer while preserving the existing OutputStreamWriter-based encoding path.

Co-Authored-By: Claude <noreply@anthropic.com>

* changelog

* perf(core): Remove redundant event map copies

Avoid creating temporary maps when applying scope and options tags or scope extras. The event setters already copy these maps, so this preserves snapshot semantics while reducing allocation overhead.

Co-Authored-By: Claude <noreply@anthropic.com>

* changelog

* changelog

* perf(core): Short-circuit combined scope collections

Avoid allocating merged collection copies when only one combined scope contains values. This extends the breadcrumbs optimization to tags, attributes, extras, and attachments while preserving merge behavior when multiple scopes contribute data.

Co-Authored-By: Claude <noreply@anthropic.com>

* changelog

* perf(android): Use TimeZone.getDefault for device timezone

Avoid constructing a Calendar only to read the default device timezone. The locale passed to Calendar does not affect the timezone value, so TimeZone.getDefault returns the same value with less work during device context collection.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Replace Calendar with Date in DateUtils

Avoid constructing Calendar instances when DateUtils only needs the current epoch millis or a Date for an existing millis value. Date stores epoch millis without timezone state, so the returned values are unchanged while avoiding unnecessary Calendar allocation and field computation.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Reduce JsonWriter stack allocation

Shrink the vendored JsonWriter nesting stack from 32 entries to 8 entries. The stack still grows on demand for deeply nested payloads, while common SDK serialization avoids the larger initial array allocation.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Lazily allocate Breadcrumb data

Avoid allocating a ConcurrentHashMap for breadcrumbs that never set data. Initialize the data map on first write while preserving concurrent writes with double-checked locking.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Reduce context serialization allocations

Use sorted key arrays when serializing contexts to avoid allocating an ArrayList for each serialization. This preserves deterministic key ordering while keeping the snapshot representation smaller.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Lazily allocate reflection serializer state

Defer creation of the reflection serializer visiting set until reflection serialization is actually needed. Normal SDK payload serialization uses explicit serializers, so this avoids an unused HashSet allocation for each writer.

* perf(core): Lazily create reflection JSON serializer

Defer creation of JsonReflectionObjectSerializer until unknown-object reflection serialization is needed. Normal SDK payloads use explicit serializers, so this avoids allocating unused reflection serializer state for each writer.

* fix(android): Preserve locale timezone extension

Keep the Calendar-based timezone path for Android 13+ locales that carry a Unicode tz extension. This preserves the existing device timezone behavior while keeping the direct default timezone fast path for normal locales.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Replace ISO8601 timestamp handling

Replace the Calendar-backed vendored ISO8601 formatting and parsing path with a small Sentry-specific utility that works directly from epoch milliseconds.

This avoids formatter and parser allocations on timestamp-heavy serialization paths while keeping the existing DateUtils API as the facade.

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(core): Move ISO8601 utility to vendor package

Move the Sentry ISO8601 helper under the vendor package and mark it as internal API so the adapted public-domain date conversion code is isolated from core SDK classes.

Update attribution metadata to reflect the public-domain dedication source.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(core): Avoid cloning Date getters

* fix(core): Preserve ISO8601 utility compatibility

Match edge-case behavior from the previous vendored ISO8601 utility for date-only timestamps, trailing characters after Z, and Gregorian cutover dates.

* fix(core): Preserve mutable breadcrumb data access

Initialize the lazy breadcrumb data map when callers request the full map. This keeps getData() mutable for existing callers while preserving lazy allocation for breadcrumbs that only serialize or read individual values.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(android): Explain timezone Calendar fallback

Document why Android 13+ locales with Unicode timezone extensions keep using Calendar while normal locales use the default timezone directly for performance.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Avoid KeySetView in context serialization

Use ConcurrentHashMap.keys() when creating sorted context key snapshots so the serialization path stays compatible with Android API 21. Keep the array snapshot optimization without relying on KeySetView, which AnimalSniffer rejects for the SDK's minSdk.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(core): Add breadcrumb timestamp serialization coverage

Cover that breadcrumbs backed by timestamp milliseconds serialize the same timestamp as breadcrumbs backed by Date for the same instant.

* fix(core): Parse date-only timestamps with timezones

Preserve ISO8601 parser compatibility for date-only values that include a timezone suffix. Keep modern date-only timezone parsing on the fast path and add parity coverage against the previous parser.

* docs(core): Add timezone changelog entry

* docs(core): Add DateUtils changelog entry

* docs(core): Add JsonWriter changelog entry

* docs(core): Add breadcrumb changelog entry

* docs(core): Add contexts changelog entry

* docs(core): Add reflection state changelog entry

* docs(core): Add reflection serializer changelog entry

* docs(core): Add ISO8601 handling changelog entry

* docs(core): Add Date getter changelog entries

* changelog

---------

Co-authored-by: Claude <noreply@anthropic.com>
A
Alexander Dinauer committed
2ebf90a0da3127c7b3adee4a86fe3c142bc6fa26
Parent: e0a2a6e
Committed by GitHub <noreply@github.com> on 6/25/2026, 1:45:49 PM