Efficiently returning two values ​​from a Java function

Does anyone know if there is a way to return two values ​​from Java with (close to zero) overhead? I am looking for only two values ​​- I have several use cases from processing an array of bytes (and I need to return the value and the next starting position) to try to return the value with the error code, to make some kind of ugliness with the correction, and the whole and fractional part .

I don’t go with some really ugly hacks. The feature is small, and Hotspot happily embeds it. So, now I just need Hotspot to completely lose the creation of any object or bit offset.

If I limit my return values ​​to ints, I tried to pack them in a long one, but even after inlining, Hotspot may not seem like all bit shifts and masks actually do anything, and it happily packs and unpacks ints into one and the same values ​​(obviously, the place where the Hotspot voice optimizer needs help). But at least I am not creating an object.

My more complicated case is when one of the elements I need to return is a link and the other a long or another link (for the int case, I think I can compress OOP and use the bit packing described above).

Has anyone tried to get Hotspot to create garbage-free code for this? The worst case right now is that I have to carry an item with me and hand it over, but I would like to keep it alone. Locals are really expensive (hash requests) and they must be reentrant.

+2
source share
3 answers
Optimization

-XX:+EliminateAllocations (enabled by default in Java 8) is great for this.

Whenever you return new Pair(a, b) right at the end of the called method and immediately use the result in the caller, the JVM will most likely perform a scalar replacement if the called user is nested.

A simple experiment shows that when returning an object there is almost no overhead. This is not only an effective way, but also the most readable one.

 Benchmark Mode Cnt Score Error Units ReturnPair.manualInline thrpt 30 127,713 ± 3,408 ops/us ReturnPair.packToLong thrpt 30 113,606 ± 1,807 ops/us ReturnPair.pairObject thrpt 30 126,881 ± 0,478 ops/us ReturnPair.pairObjectAllocated thrpt 30 92,477 ± 0,621 ops/us 

Test:

 import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.ThreadLocalRandom; @State(Scope.Benchmark) public class ReturnPair { int counter; @Benchmark public void manualInline(Blackhole bh) { bh.consume(counter++); bh.consume(ThreadLocalRandom.current().nextInt()); } @Benchmark public void packToLong(Blackhole bh) { long packed = getPacked(); bh.consume((int) (packed >>> 32)); bh.consume((int) packed); } @Benchmark public void pairObject(Blackhole bh) { Pair pair = getPair(); bh.consume(pair.a); bh.consume(pair.b); } @Benchmark @Fork(jvmArgs = "-XX:-EliminateAllocations") public void pairObjectAllocated(Blackhole bh) { Pair pair = getPair(); bh.consume(pair.a); bh.consume(pair.b); } public long getPacked() { int a = counter++; int b = ThreadLocalRandom.current().nextInt(); return (long) a << 32 | (b & 0xffffffffL); } public Pair getPair() { int a = counter++; int b = ThreadLocalRandom.current().nextInt(); return new Pair(a, b); } static class Pair { final int a; final int b; Pair(int a, int b) { this.a = a; this.b = b; } } } 
+5
source

Your described solution is almost as good as you can get in Hotspot - passing an object to hold return values ​​and mutate it. (Values ​​of Java 10 types can do something better here, but I don’t think at the prototype stage.)

This suggests that small short-lived objects are actually not so far from zero. Garbage collection of short-lived objects is deliberately extremely cheap.

0
source

I had to deal with this problem and found out that the best way is to create a simple final class with public fields and then pass it in a parameter to your method. Click the results on this instance.

If you have a loop, try reusing this instance for as long as possible.

Having setters and getters, in Java 7 (when I did this) had very little overhead. The same thing happens with instances of new objects in each cycle.

0
source

All Articles