Short answer
In old JDKs (pre-7u6) substring() shared the parent's backing char array, so keeping a tiny substring pinned a huge string in memory; modern substring copies, so that specific leak is gone but copying has its own cost.
Explanation
The current pitfall is splitting or interning huge inputs at scale, which inflates the heap and string pool. For very large text, prefer streaming/CharSequence views, process in chunks, and avoid interning attacker-controlled strings, which can exhaust the pool.
Common mistakes
- Holding small substrings of huge strings in very old JDKs without knowing why it leaked.
- Keeping big split arrays in caches longer than needed.