From b48ccf260580981402638b4f64514c5d09b62429 Mon Sep 17 00:00:00 2001 From: tonycpsu Date: Sun, 12 Jul 2026 02:11:24 -0400 Subject: [PATCH] Bound RecipientStore address cache to prevent unbounded memory growth (#2088) 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. Claude-Session: https://claude.ai/code/session_01HHzM2XLKQoX9iraEdhoh3h Co-authored-by: Claude Opus 4.6 --- .../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