Preface
Program performance is directly affected by code quality. This time, I will introduce some tips and practices in coding. Although some seemingly insignificant programming skills can bring about multiple improvements in system performance, it is worth noting.
Use caution exceptions
In Java development, try-catch is often used for error capture, but try-catch statements are very bad for system performance. Although it is impossible to detect the loss of performance in a try-catch, once a try-catch statement is applied to a loop or traversing the body, it will cause great damage to the system performance.
The following is a sample code that applies try-catch to the loop body:
@Test public void test11() { long start = System.currentTimeMillis(); int a = 0; for(int i=0;i<1000000000;i++){ try { a++; }catch (Exception e){ e.printStackTrace(); } } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
The result of the above code is:
useTime:10
Here's a piece of code that moves try-catch out of the loop and improves performance by nearly half. As follows:
@Test public void test(){ long start = System.currentTimeMillis(); int a = 0; try { for (int i=0;i<1000000000;i++){ a++; } }catch (Exception e){ e.printStackTrace(); } long useTime = System.currentTimeMillis()-start; System.out.println(useTime); }
Operation results:
useTime:6
Using local variables
The parameters passed when calling the method and the temporary variables created in the call are stored in the Stack, which is fast. Other variables, such as static variables, instance variables, etc., are created in Heap, which is slower.
Here's a section of code that uses local variables to compute:
@Test public void test11() { long start = System.currentTimeMillis(); int a = 0; for(int i=0;i<1000000000;i++){ a++; } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:5
Replace local variables with static variables of the class:
static int aa = 0; @Test public void test(){ long start = System.currentTimeMillis(); for (int i=0;i<1000000000;i++){ aa++; } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:94
From the results of the above two operations, it can be seen that the access speed of local variables is much faster than that of class member variables.
Bit operation instead of multiplication and division
Among all operations, bit operation is the most efficient. Therefore, we can try to use bit operation instead of partial arithmetic operation to improve the speed of the system. The most typical is to optimize the multiplication and division of integers.
Here's a piece of code that uses arithmetic:
@Test public void test11() { long start = System.currentTimeMillis(); int a = 0; for(int i=0;i<1000000000;i++){ a*=2; a/=2; } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:1451
The multiplication and division operation in the loop body is replaced by the equivalent bit operation. The code is as follows:
@Test public void test(){ long start = System.currentTimeMillis(); int aa = 0; for (int i=0;i<1000000000;i++){ aa<<=1; aa>>=1; } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:10
The last two pieces of code perform exactly the same function, multiplying integers by 2 and dividing them by 2 in each loop. But the running results are very time-consuming, so the efficiency of bit operation is obvious.
Extract expressions
In the process of software development, programmers can easily consciously or unintentionally make code do some "duplicate work". In most cases, due to the high speed of computer operation, these "duplicate work" will not pose too much threat to performance, but if you want to maximize the performance of the system, extracting these "duplicate work" is quite meaningful.
For example, two arithmetic calculations are performed in the following code:
@Test public void testExpression(){ long start = System.currentTimeMillis(); double d = Math.random(); double a = Math.random(); double b = Math.random(); double e = Math.random(); double x,y; for(int i=0;i<10000000;i++){ x = d*a*b/3*4*a; y = e*a*b/3*4*a; } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:21
Looking carefully, it can be found that the latter half of the two computational expressions are identical, which means that the expressions of the same part are recalculated in each cycle.
After a few improvements, it becomes the following:
@Test public void testExpression99(){ long start = System.currentTimeMillis(); double d = Math.random(); double a = Math.random(); double b = Math.random(); double e = Math.random(); double p,x,y; for(int i=0;i<10000000;i++){ p = a*b/3*4*a; x = d*p; y = e*p; } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:11
Through the operation results, we can see the specific optimization effect.
Similarly, if a time-consuming operation needs to be performed in a certain cycle, the execution result is always unique in the circulatory body, and should be extracted into the circulatory body.
For example, the following code:
for(int i=0;i<100000;i++){ x[i] = Math.PI*Math.sin(y)*i; }
The following code should be improved:
//Extracting complex, fixed results of business logic to be processed outside the loop double p = Math.PI*Math.sin(y); for(int i=0;i<100000;i++){ x[i] = p*i; }
Use arrayCopy()
Array replication is a very frequently used function, and JDK provides an efficient API to implement it.
/** * @param src the source array. * @param srcPos starting position in the source array. * @param dest the destination array. * @param destPos starting position in the destination data. * @param length the number of array elements to be copied. * @exception IndexOutOfBoundsException if copying would cause * access of data outside array bounds. * @exception ArrayStoreException if an element in the <code>src</code> * array could not be stored into the <code>dest</code> array * because of a type mismatch. * @exception NullPointerException if either <code>src</code> or * <code>dest</code> is <code>null</code>. */ public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
If you need to replicate arrays in your application, you should use this function instead of implementing it yourself.
Here are some examples:
@Test public void testArrayCopy(){ int size = 100000; int[] array = new int[size]; int[] arraydest = new int[size]; for(int i=0;i<array.length;i++){ array[i] = i; } long start = System.currentTimeMillis(); for (int k=0;k<1000;k++){ //Replication System.arraycopy(array,0,arraydest,0,size); } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:59
Correspondingly, if you implement array replication by yourself in a program, the equivalent code is as follows:
@Test public void testArrayCopy99(){ int size = 100000; int[] array = new int[size]; int[] arraydest = new int[size]; for(int i=0;i<array.length;i++){ array[i] = i; } long start = System.currentTimeMillis(); for (int k=0;k<1000;k++){ for(int i=0;i<size;i++){ arraydest[i] = array[i]; } } long useTime = System.currentTimeMillis()-start; System.out.println("useTime:"+useTime); }
Operation results:
useTime:102
The effect can be seen from the operation results.
Because the System.arraycopy() function is a native function, the performance of the native function is usually better than that of the ordinary function. For performance reasons only, native functions should be invoked as much as possible during program development.
It will be updated continuously later...