Skip to content

Commit 3b13f34

Browse files
adinauerclaude
andcommitted
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>
1 parent 06fb38b commit 3b13f34

3 files changed

Lines changed: 27 additions & 8 deletions

File tree

sentry/src/main/java/io/sentry/MonitorContexts.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
import io.sentry.util.Objects;
44
import io.sentry.vendor.gson.stream.JsonToken;
55
import java.io.IOException;
6-
import java.util.Collections;
7-
import java.util.List;
6+
import java.util.Arrays;
87
import java.util.concurrent.ConcurrentHashMap;
98
import org.jetbrains.annotations.NotNull;
109
import org.jetbrains.annotations.Nullable;
1110

1211
public final class MonitorContexts extends ConcurrentHashMap<String, Object>
1312
implements JsonSerializable {
1413
private static final long serialVersionUID = 3987329379811822556L;
14+
private static final String[] EMPTY_KEYS = new String[0];
1515

1616
public MonitorContexts() {}
1717

@@ -49,8 +49,8 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger
4949
throws IOException {
5050
writer.beginObject();
5151
// Serialize in alphabetical order to keep determinism.
52-
final List<String> sortedKeys = Collections.list(keys());
53-
Collections.sort(sortedKeys);
52+
final String[] sortedKeys = keySet().toArray(EMPTY_KEYS);
53+
Arrays.sort(sortedKeys);
5454
for (final String key : sortedKeys) {
5555
final Object value = get(key);
5656
if (value != null) {

sentry/src/main/java/io/sentry/protocol/Contexts.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414
import io.sentry.util.Objects;
1515
import io.sentry.vendor.gson.stream.JsonToken;
1616
import java.io.IOException;
17-
import java.util.Collections;
17+
import java.util.Arrays;
1818
import java.util.Enumeration;
1919
import java.util.HashMap;
20-
import java.util.List;
2120
import java.util.Map;
2221
import java.util.Set;
2322
import java.util.concurrent.ConcurrentHashMap;
@@ -28,6 +27,7 @@
2827
public class Contexts implements JsonSerializable {
2928
private static final long serialVersionUID = 252445813254943011L;
3029
public static final String REPLAY_ID = "replay_id";
30+
private static final String[] EMPTY_KEYS = new String[0];
3131

3232
private final @NotNull ConcurrentHashMap<String, Object> internalStorage =
3333
new ConcurrentHashMap<>();
@@ -302,8 +302,8 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger
302302
throws IOException {
303303
writer.beginObject();
304304
// Serialize in alphabetical order to keep determinism.
305-
final List<String> sortedKeys = Collections.list(keys());
306-
Collections.sort(sortedKeys);
305+
final String[] sortedKeys = internalStorage.keySet().toArray(EMPTY_KEYS);
306+
Arrays.sort(sortedKeys);
307307
for (final String key : sortedKeys) {
308308
final Object value = get(key);
309309
if (value != null) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.sentry
2+
3+
import io.sentry.protocol.SerializationUtils
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
import org.mockito.kotlin.mock
7+
8+
class MonitorContextsTest {
9+
@Test
10+
fun `serializes entries in alphabetical order`() {
11+
val contexts =
12+
MonitorContexts().apply {
13+
put("b", 2)
14+
put("a", 1)
15+
}
16+
17+
assertEquals("{\"a\":1,\"b\":2}", SerializationUtils.serializeToString(contexts, mock()))
18+
}
19+
}

0 commit comments

Comments
 (0)