Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the automatic packing performance of Java

2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

The main content of this article is to explain "how to use Java auto-packing performance". Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to use the Java auto-packing feature.

The basic data types of Java (int, double, char) are not objects. But because much of the Java code needs to deal with objects (Object), Java provides wrapper classes (Integer, Double, Character) for all basic types. With automatic boxing, you can write the following code

Character boxed = 'a'; char unboxed = boxed

The compiler automatically converts it to

Character boxed = Character.valueOf ('a'); char unboxed = boxed.charValue ()

However, the Java virtual machine does not always understand such processes, so it is critical to avoid unnecessary packing in order to achieve good system performance. This is also the reason why special types such as OptionalInt and IntStream exist. In this article, I will outline one reason why it is difficult for JVM to eliminate autoboxing.

Example

For example, we want to calculate the editing distance (Levenshtein distance) for any type of data, as long as the data can be seen as a sequence:

Public class Levenshtein {private final Function > asList; public Levenshtein (Function > asList) {this.asList = asList;} public int distance (T a, T b) {/ / Wagner-Fischer algorithm, with two active rows List aList = asList.apply (a); List bList = asList.apply (b); int bSize = bList.size (); int [] row0 = new int [bSize + 1]; int [] row1 = new int [bSize + 1]; for (int I = 0; I row0 [I] = I } for (int I = 0; I < bSize; + + I) {U ua = aList.get (I); row1 [0] = row0 [0] + 1; for (int j = 0; j < bSize; + + j) {U ub = bList.get (j); int subCost = row0 [j] + (ua.equals (ub)? 0: 1); int delCost = row0 [j + 1] + 1; int insCost = row1 [j] + 1 Row1 [j + 1] = Math.min (subCost, Math.min (delCost, insCost));} int [] temp = row0; row0 = temp;} return row0 [bSize];}}

This class can calculate the editing distance of two objects as long as they can be treated as List. If you want to calculate the distance of type String, you need to convert String to type List:

Public class StringAsList extends AbstractList {private final String str; public StringAsList (String str) {this.str = str;} @ Override public Character get (int index) {return str.charAt (index); / / Autoboxing!} @ Override public int size () {return str.length ();}}. Levenshteinlev = new Levenshtein (StringAsList::new); lev.distance ("autoboxing is fast", "autoboxing is slow"); / / 4

Because of the way Java generics are implemented, there can be no List types, so List and boxing operations are provided. (note: in Java10, this restriction may be removed. )

To see the results on the code hot path (hot path), JMH integrates the Linux tool perf, which allows you to view the JIT compilation results of the hottest code blocks. To view the assembly code, you need to install the hsdis plug-in. I provide downloads on AUR, and Arch users can get them directly. Add the-prof perfasm command to the JMH command line, and you can see the result:

To test the performance of the distance () method, you need to do a benchmark test. Microbenchmarking in Java is difficult to guarantee accuracy, but fortunately OpenJDK provides JMH (Java Microbenchmark Harness), which can help us solve most of the problems. If you are interested, it is recommended that you read the documentation and examples; it will appeal to you. The following is the benchmark test:

@ State (Scope.Benchmark) public class MyBenchmark {private Levenshtein lev = new Levenshtein (StringAsList::new); @ Benchmark @ BenchmarkMode (Mode.AverageTime) @ OutputTimeUnit (TimeUnit.NANOSECONDS) public int timeLevenshtein () {return lev.distance ("autoboxing is fast", "autoboxing is slow");}}

Returns the result of the method so that JMH can do something to make the system think that the return value will be used to prevent redundant code from affecting the result. )

Here are the results:

$java- jar target/benchmarks.jar-f 1-wi 8-I 8 # JMH 1.10.2 (released 3 days ago) # VM invoker: / usr/lib/jvm/java-8-openjdk/jre/bin/java # VM options: # Warmup: 8 iterations, 1 s each # Measurement: 8 iterations, 1 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: com.tavianator.boxperf.MyBenchmark.timeLevenshtein # Run progress: 0.00% complete ETA 00:00:16 # Fork: 1 of 1 # Warmup Iteration 1: 1517.495 ns/op # Warmup Iteration 2: 1503.096 ns/op # Warmup Iteration 3: 1402.069 ns/op # Warmup Iteration 4: 1480.584 ns/op # Warmup Iteration 5: 1385.345 ns/op # Warmup Iteration 6: 1474.657 ns/op # Warmup Iteration 7: 1436.749 ns/op # Warmup Iteration 8: 1463.526 ns/op Iteration 1: 1446.033 ns/op Iteration 2: 1420.199 ns/op Iteration 3 : 1383.017 ns/op Iteration 4: 1443.775 ns/op Iteration 5: 1393.142 ns/op Iteration 6: 1393.313 ns/op Iteration 7: 1459.974 ns/op Iteration 8: 1456.233 ns/op Result "timeLevenshtein": 1424.461 ±(99.9) 59.574 ns/op [Average] (min Avg, max) = (1383.017, 1424.461, 1459.974), stdev = 31.158 CI (99.9%): [1364.887, 1484.034] (assumes normal distribution) # Run complete. Total time: 00:00:16 Benchmark Mode Cnt Score Error Units MyBenchmark.timeLevenshtein avgt 8 1424.461 ±59.574 ns/op

Analysis.

To see the results on the code hot path (hot path), JMH integrates the Linux tool perf, which allows you to view the JIT compilation results of the hottest code blocks. To view the assembly code, you need to install the hsdis plug-in. I provide downloads on AUR, and Arch users can get them directly. Add the-prof perfasm command to the JMH command line, and you can see the result:

$java-jar target/benchmarks.jar-f 1-wi 8-I 8-prof perfasm... Cmp $0x7fcmp% eax jg 0x00007fde989a6148; * if_icmpgt;-java.lang.Character::valueOf@3 (line 4570);-com.tavianator.boxperf.StringAsList::get@8 (line 14);-com.tavianator.boxperf.StringAsList::get@2; (line 5);-com.tavianator.boxperf.Levenshtein::distance@121 (line 32) cmp $0x80 jae 0x00007fde989a6103% Eax jae 0x00007fde989a6103; * aaload;-java.lang.Character::valueOf@ 10 (line 4571) -com.tavianator.boxperf.StringAsList::get@8 (line 14);-com.tavianator.boxperf.StringAsList::get@ 2 (line 5);-com.tavianator.boxperf.Levenshtein::distance@121 (line 32).

There is a lot of output, but the above shows that the packing has not been optimized. Why compare it with the content of 0x7f/0 × 80? The reason is that the value of Character.valueOf () comes from:

Private static class CharacterCache {private CharacterCache () {} static final Character cache [] = new Character [127th + 1]; static {for (int I = 0; I < cache.length; I +) cache [I] = new Character ((char) I);}} public static Character valueOf (char c) {if (c return CharacterCache.cache [(int) c];} return new Character (c);}

As you can see, the Java syntax standard states that the Character objects of the first 127th char are placed in the buffer pool, and when the result of Character.valueOf () is in it, the objects of the buffer pool are returned directly. The goal is to reduce memory allocation and garbage collection, but in my opinion this is premature optimization. And it interferes with other optimizations. JVM cannot determine Character.valueOf (c). CharValue () = = c because it does not know the contents of the buffer pool. So JVM takes a Character object from the buffer pool and reads its value, and the result is the same content as c.

Solution method

The solution is simple:

@ @-11 index 7 + 11 public class StringAsList extends AbstractList {@ Override public Character get (int index) {- return str.charAt (index); / / Autoboxing! + return new Character (str.charAt (index));}

@ Override

Using explicit boxing instead of autoboxing avoids calling Character.valueOf (), so that JVM can easily understand the code:

Private final char value; public Character (char value) {this.value = value;} public char charValue () {return value;}

Although a memory allocation is added to the code, JVM understands the meaning of the code and fetches char characters directly from String. The performance improvement is significant:

$java-jar target/benchmarks.jar-f 1-wi 8-I 8... # Run complete. Total time: 00:00:16 Benchmark Mode Cnt Score Error Units MyBenchmark.timeLevenshtein avgt 8 1221.151 ±58.878 ns/op

The speed has increased by 14%. The-prof perfasm command shows that after the improvement, the char value is taken directly from the String and compared in the register:

Movzwl 0x10 (% rsi,%rdx,2),% r11d; * caload

;-java.lang.String::charAt@27 (line 648)

;-com.tavianator.boxperf.StringAsList::get@9 (line 14)

;-com.tavianator.boxperf.StringAsList::get @ 2 (line 5)

;-com.tavianator.boxperf.Levenshtein::distance@121 (line 32)

Cmp% r11ddepartment% r10d

Je 0x00007faa8d404792; * if_icmpne

;-java.lang.Character::equals@18 (line 4621)

;-com.tavianator.boxperf.Levenshtein::distance@137 (line 33)

At this point, I believe you have a deeper understanding of "how to use the Java auto-packing performance". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report