How to measure the memory cost of lambdas in Java 25?

14 hours ago 3
ARTICLE AD BOX

If I run Java 25 JShell with Java Object Layout library (JOL) without any JVM settings and measure the memory cost in bytes of a Predicate<String> I see the following:

$ jshell --class-path ~/.m2/repository/org/openjdk/jol/jol-core/0.17/jol-core-0.17.jar | Welcome to JShell -- Version 25.0.1 | For an introduction type: /help intro jshell> Predicate<String> predicate = (x) -> true predicate ==> $Lambda/0x0000080001048000@439f5b3d jshell> import org.openjdk.jol.info.* jshell> IO.println(GraphLayout.parseInstance(predicate).toFootprint()) REPL.$JShell$2$$Lambda/0x0000080001048000@439f5b3dd footprint: COUNT AVG SUM DESCRIPTION 1 16 16 REPL.$JShell$2$$Lambda/0x0000080001048000 1 16 (total)

If I run the same code with Compact Object Headers (COH) enabled, I see the following:

$ jshell --class-path ~/.m2/repository/org/openjdk/jol/jol-core/0.17/jol-core-0.17.jar -R-XX:+UseCompactObjectHeaders | Welcome to JShell -- Version 25.0.1 | For an introduction type: /help intro jshell> Predicate<String> predicate = (x) -> true predicate ==> $Lambda/0x00000fe001049400@1d56ce6a jshell> import org.openjdk.jol.info.* jshell> IO.println(GraphLayout.parseInstance(predicate).toFootprint()) REPL.$JShell$2$$Lambda/0x00000fe001049400@1d56ce6ad footprint: COUNT AVG SUM DESCRIPTION 1 8 8 REPL.$JShell$2$$Lambda/0x00000fe001049400 1 8 (total)

While it may seem I have answered my own question here, I am not sure that I have.

Will the 16 bytes (COH off) or 8 bytes (COH on) for a stateless lambda be allocated once and hoisted statically or allocated on every encounter of the lambda in code?

I can write the code to load the lambda instances in a list as follows.

List<Predicate<String>> list = IntStream.range(0, 1000000) .<Predicate<String>>mapToObj(each -> (x) -> x.isEmpty()) .toList()

Will this give me the answer I am looking for for stateless lambdas? Can this vary by JVM implementation? What happens to the cost if the lambda includes a local variable or field capture, like the following?

List<Predicate<String>> list = IntStream.range(0, 1000000) .<Predicate<String>>mapToObj( each -> (x) -> x.isEmpty() || each % 2 == 0) .toList()
Read Entire Article