Skip to content

Conversation

@johannesodland
Copy link

Adding a new PR here to start the discussion on solving #20 again.

This PR switches to WeakMap (as in #23), but uses string objects as keys. This will have a performance impact, and change the output from vhtml() from string primitives to string objects.

The question is if it's worth taking the performance impact to solve both #20 and #34.

TimDaub added a commit to attestate/vhtml-memory-safe that referenced this pull request Oct 21, 2025
Problem:
- Original code used `let sanitized = {}` which never garbage collects
- This causes unbounded memory growth in SSR scenarios
- Heap analysis showed ~5,400 concatenated strings per feed generation

Solution:
- Replace plain object with LRUCache from lru-cache package
- Cap at 10,000 entries (~2 feed generations worth)
- Count-based eviction with 5 MB safety cap
- Maintains string primitives (no String object overhead like WeakMap approach)

Based on heap analysis:
- ~21,500 strings/minute growth rate
- ~5,400 strings per feed (15s regeneration cycle)
- Average string size: ~32 bytes
- 10,000 entries = ~320 KB stable memory footprint

Related: developit#20, developit#34, developit#43
TimDaub added a commit to attestate/vhtml-memory-safe that referenced this pull request Oct 21, 2025
- Replace LRU cache with WeakMap approach from PR developit#43
- Use String objects as WeakMap keys for automatic garbage collection
- Memory bounded to active rendering context, no manual management needed
- Update tests to use valueOf() to convert String objects to primitives

Fixes developit#20, developit#34
Based on: developit#43
@TimDaub
Copy link

TimDaub commented Oct 21, 2025

This won't work because we're now returning strings

TimDaub added a commit to attestate/vhtml-memory-safe that referenced this pull request Oct 21, 2025
- Replace unbounded cache with WeakMap
- Return String objects instead of primitives
- String objects can be WeakMap keys and are GC'd automatically
- No eviction issues - entries only released when truly unreferenced
- Requires calling .valueOf() on final result before serialization

This approach is based on PR developit#43 but adapted for server-side usage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants