From ffbbcabf8d16a954b6aba0f5b68d017e0865d418 Mon Sep 17 00:00:00 2001 From: Tony Cebzanov Date: Sat, 11 Jul 2026 21:57:48 -0400 Subject: [PATCH] Bound RecipientStore address cache to prevent unbounded memory growth The recipientAddressCache grows with every unique ServiceId resolved via findByServiceId() and entries are never evicted. In a long-running daemon handling group messages from many contacts, this map grows monotonically. Replace the unbounded HashMap with an LRU-bounded LinkedHashMap (access order, max 2000 entries). Evicted entries are reloaded from SQLite on next access via an indexed lookup, so correctness is preserved. Co-Authored-By: Claude Opus 4.6 Claude-Session: https://claude.ai/code/session_01HHzM2XLKQoX9iraEdhoh3h --- .../manager/storage/recipients/RecipientStore.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index 90ea1baa..dbc7620c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -30,6 +30,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -51,7 +52,16 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re private final Map recipientsMerged = new HashMap<>(); - private final Map recipientAddressCache = Collections.synchronizedMap(new HashMap<>()); + private static final int MAX_RECIPIENT_CACHE_SIZE = 2000; + + private final Map recipientAddressCache = Collections.synchronizedMap( + new LinkedHashMap<>(16, 0.75f, true) { + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > MAX_RECIPIENT_CACHE_SIZE; + } + }); public static void createSql(Connection connection) throws SQLException { // When modifying the CREATE statement here, also add a migration in AccountDatabase.java