Https://blog.coding.net/blog/java-coding-performance
- 1 Visual VMS
- 2 Optimizing A
- 2.1 Background
- 2.2 Original implementation
- 2.3 Anatomy
- 2.4 Solutions
- 2.5 Core Code
- 3 Optimization Two
- 3.1 Background
- 3.2 Original Implementation
- 3.3 Anatomy
- 3.4 Program & Code
- 4 results
1 Visual VMS
One of the interfaces in the project, in a certain scenario (large data volume), is unbearable for performance.
So how do you have the tools to locate the code that is causing the performance problem? There are actually many, here we use Visual VMs.
The Visual VM is a graphical tool for analyzing Java applications, enabling performance analysis and tuning of Java applications. If you are using Java 7 or Java 8, you can find the tool directly in the bin directory of the JDK, named JVISUALVM. Of course, you can download it on the official website.
The methods for analyzing the performance of an interface using Visual VMS are as follows:
The results are shown below:
Through, we can see that the more time-consuming methods for Resolvebyteposition and Rest,getfile and CurrentUser are network requests that are temporarily not considered.
2 Optimize one 2.1 background
First, take the Resolvebyteposition method of surgery. To make it easier to explain the use of resolvebyteposition, for example.
Given a string chars with the string's UTF-8 binary array (spaces are used to separate character data, the actual does not exist):
chars = "just一个test";bytes = "6A 75 73 74 E4B880 E4B8AA 74 65 73 74";
The resolvebyteposition is used to solve the problem of bytepos calculation of offset charpos in chars given a bytes offset. Like what:
bytePos = 0 (6A) 对应 charPos = 0 (j)bytePos = 1 (75) 对应 charPos = 1 (u)
If you use Array[start:] to represent a new array of array elements to the end from the subscript start, then there are:
bytes[bytePos:] = chars[charPos:]
Example:
bytes[0:] = chars[0:]bytes[1:] = chars[1:]bytes[10:] = chars[6:]
2.2 Original implementation
Understand the role of resolvebyteposition, look at its implementation
public int resolveBytePosition(byte[] bytes, int bytePos) { return new String(slice(bytes, 0, bytePos)).length();}
The method is simple and rough, can calculate the result accurately, but the disadvantage is obvious, the construction of the string frequently has a great effect on the performance. The Visual VM confirms our inference by clicking on the snapshot to see a more detailed method call time-consuming.
2.3 Anatomy
To make it easier to parse the problem, we draw the following table to show the UTF-8 and Unicode binary data for each character:
|
J |
u |
s |
t |
a |
|
| t
e |
s |
t |
| UTF-8 |
6A |
75 |
73 |
74 |
e4b880 |
E4b8aa |
74 |
65 |
73 |
74 |
| Unicode |
6A |
75 |
73 |
74 |
4E00 |
4e2a |
74 |
65 |
73 |
74 |
We then convert the byte data to the byte length:
|   |
j |
u |
s |
t |
one |
|
t |
e |
s |
t |
| UTF-8 |
1 |
1 |
1 |
1 |
3 |
3 |
1 |
1 |
1 |
1 |
| Unicode |
1 |
1 |
1 |
1 |
2 |
2 |
1 |
1 |
1 |
1 |
In Java, a char is used to indicate that Unicode,char is 2 bytes long, so a char is sufficient to represent any one of the characters in the example.
We use a cell to represent a byte (UTF-8) or a char (Unicode), and to number the cell, get the following table:
|
J |
u |
s |
t |
a |
|
| t
e |
s |
t |
| bytes |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
| Chars |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
The following correspondence can be drawn
bytes[0:] = chars[0:]bytes[1:] = chars[1:]bytes[2:] = chars[2:]bytes[3:] = chars[3:]bytes[4:] = chars[4:]bytes[7:] = chars[5:]bytes[10:] = chars[6:]... ...
2.4 Solutions
In this step, efficient algorithms are already on the horizon. The algorithm is as follows:
The character UTF-8 the binary length of the data is not 1, which is called the feature point. Each character is a byte length except for the feature point. Note the correspondence of all the feature points, and for a given bytepos, we can calculate the Charpos by the formula.
The formula is:
charPos = bytePos - preBytePos + preCharPos
Example:
In this example, there are two feature points 一 , 个 which are recorded as:
bytes[6:] = chars[4:]bytes[9:] = chars[5:]
If given Bytepos 10, first find the correspondence of the previous feature point 9 (Prebytepos), 5 (Precharpos), according to the formula (10-9) + 5 = 6.
2.5 Core Code
The algorithm also has a more critical problem to solve, that is, to efficiently calculate the byte length of a char. The algorithm for calculating the byte length of char references the StackOverflow.
Compute feature Point private int[][] Calcspecialpos (String str) {arraylist<int[]> Specialpos = new Arraylist<> ()Specialpos.add (new int[] {0, 0});int lastcharpost = 0;int lastbytepos = 0;Charset UTF8 = charset.forname ("UTF-8");Charsetencoder encoder = Utf8.newencoder ();Charbuffer input = Charbuffer.wrap (Str.tochararray ());Bytebuffer output = bytebuffer.allocate (10);int limit = Input.limit ();while (Input.position () < limit) {Output.clear ();Input.mark ();Input.limit (Math.min (input.position () + 2, input.capacity ()));if (Character.ishighsurrogate (Input.get ()) &&! Character.islowsurrogate (Input.get ())) {Malformed Surrogate pairlastcharpost++;}Input.limit (Input.position ());Input.reset ();Encoder.encode (input, output, false);int encodedlen = Output.position ();lastcharpost++;Lastbytepos + = Encodedlen;if (Encodedlen! = 1) {//feature pointSpecialpos.add (New Int[]{lastbytepos, lastcharpost});}} Return ToArray (Specialpos);} Calculates the bytepos corresponding charposprivate int calcpos (int[][] specialpos, int bytepos) According to the feature point {//If there is only one element {0, 0), the description has no eigenvalues if (specialpos.length = = 1) return bytepos; int pos = Arrays.binarysearch (Specialp OS, new int[] {bytepos, 0}, (int[] A, int[] b), Integer.compare (A[0], b[0])); if (pos >= 0) { Retu RN Specialpos[pos][1]; } else { //If binary search not Fonund, would return (-(insertion point)-1), //So here-2 are mean-1 to ge T Insertpoint and then-1 to get previous Specialpos int[] prespecialpos = specialpos[-pos-2]; return Bytepos- Prespecialpos[0] + prespecialpos[1]; }}
3 Optimization Two 3.1 backgrounds
Next, the second function rest is resolved. The function's function is to get Jsonarray (Gson) all elements except the first element.
Since rest is called in a recursive function and the recursive stack is deep, the effect is multiplied if rest is not implemented efficiently.
3.2 Original Implementation
private JsonArray rest(JsonArray arr) { JsonArray result = new JsonArray(); if (arr.size() > 1) { for (int i = 1; i < arr.size(); i++) { result.add(arr.get(i)); } } return result;}
3.3 Anatomy
By debugging, it is not a good idea to re-build every time that a jsonarray is stored in a fairly large amount of data, for frequently-invoked scenarios.
By looking at the returned Jsonarray usage, we got another clue: just use the data inside, not the modifications.
Given that Jsonarray is implemented as final, the final scenario is determined to implement a proxy class that is customized for the needs of rest.
3.4 Program & Code
The proxy class Jsonarraywrapper the functions of first, rest, and foreach, respectively.
Class Jsonarraywrapper implements Iterable<jsonelement> {Private Jsonarray Jsonarray;private int mark;Public Jsonarraywrapper () {This.jsonarray = new Jsonarray ();This.mark = 0;}Public Jsonarraywrapper (Jsonarray Jsonarray) {This.jsonarray= Jsonarray;This.mark = 0;}Public Jsonarraywrapper (Jsonarray jsonarray, int mark) {This.jsonarray = Jsonarray;This.mark = Mark;}Public Jsonobject First () {Return Jsonarray.get (Mark) Getasjsonobject ();}Public Jsonarraywrapper Rest () {return new Jsonarraywrapper (Jsonarray, mark+1);}public int size () {Return Jsonarray.size ()-Mark;}Public jsonelement get (int n) {Return Jsonarray.get (Mark + N);}public void Add (Jsonelement jsonelement) { Jsonarray.add (jsonelement); } public void AddAll (Jsonarraywrapper jsonarraywrapper) { Jsonarraywrapper.foreach (This.jsonarray::add); } @Override public iterator< Jsonelement> iterator () { Jsonarray Jsonarray = new Jsonarray (); return Jsonarray.iterator (); } @Override public void ForEach (Consumer <? Super jsonelement> action) { for (int i=mark; i<jsonarray.size (); i++) { Action.accept (Jsonarray.get (i)); }}} /span>
4 results
After these two major optimizations, the performance issues in the code are resolved, as shown in the following:
Java Project Optimization Combat