Hello Oli, I apologize for the bad surprise on the migration. Do you have a suggestion? If you have time, feel free to offer it on GitHub as a PR. Otherwise, please create a Jira ticket so we can track this.
Thank you, Gary On Thu, Oct 29, 2026, 18:06 Gillespie, Oli via user <[email protected]> wrote: > Hi, > > After upgrading to 3.21.0, I saw a memory leak in my application related > to the changes in ToStringStyle. The new 'VISITED'[1] ThreadLocal > IdentityHashMap shows unbounded growth when used in this (admittedly > strange) fashion. > > Here's a reproducer: > > ``` > /* > * curl -fLO > https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0.jar > * java -cp commons-lang3-3.21.0.jar VisitedLeak.java // leaks > * // Invocation 1000: REGISTRY.size=1 VISITED.size=1000000 > * java -cp commons-lang3-3.21.0.jar VisitedLeak.java clean // control, no > leak > */ > import org.apache.commons.lang3.builder.*; > import java.lang.reflect.Field; > import java.util.*; > > public class VisitedLeak { > static class Item { int id; } > static class Graph { List<Object> items = new ArrayList<>() {{ for > (int i = 0; i < 999; i++) add(new Object()); }}; } > > static int size(String field) throws Exception { > Field f = ToStringStyle.class.getDeclaredField(field); > f.setAccessible(true); > return ((Map<?, ?>) ((ThreadLocal<?>) f.get(null)).get()).size(); > } > > public static void main(String[] args) throws Exception { > if (args.length == 0) new ReflectionToStringBuilder(new Graph(), > new RecursiveToStringStyle()); // start leak > for (int i = 0; i <= 1000; i++) { > if (i % 100 == 0) System.out.printf("Invocation %d: > REGISTRY.size=%d VISITED.size=%d%n", i, size("REGISTRY"), size("VISITED")); > new ReflectionToStringBuilder(new Graph(), new > RecursiveToStringStyle()).toString(); > } > } > } > ``` > prints `Invocation 1000: REGISTRY.size=1 VISITED.size=1000000`, > demonstrating the leak. > > In my application this was because of some awkward logging code: > `log.debug("...", new ReflectionToStringBuilder(...))`. toString() is not > called if debug logging is not enabled, starting the leak. Easy fix on my > side, but reporting in case you consider this a bug, or for anyone else > that might run into it. > > Oli > > [1] > https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java#L607 > > > > Amazon Development Centre (London) Ltd. Registered in England and Wales > with registration number 04543232 with its registered office at 1 > Principal Place > <https://www.google.com/maps/search/1+Principal+Place?entry=gmail&source=g>, > Worship Street, London EC2A 2FA, United Kingdom. > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > >
