I will share 11 practical tips on Java performance tuning and java Tuning
Most developers think that performance optimization is a complicated problem and requires a lot of experience and knowledge. Yes, it is not wrong. It is not easy to optimize the application to achieve the best performance, but it does not mean that you cannot do anything before getting the experience and knowledge. Below are a few suggestions and best practices that can easily be followed to help you create an application with good performance.
Most of these suggestions are based on Java, but they are not necessarily applicable to all applications and programming languages. Before sharing the Java-based performance tuning skills, let's first discuss these general performance tuning skills.
1. Do not optimize it before necessary
This may be one of the most important performance tuning techniques. You should follow common best practices and try to effectively implement your use cases. However, this does not mean replacing any standard library or building complex optimizations before proving it is necessary.
In most cases, premature optimization takes a lot of time, making it difficult to read and maintain the code. Even worse, these optimizations usually do not bring any benefit, because you spend a lot of time optimizing the non-critical part of the application.
So how do you prove that you need to optimize something?
First, you need to determine the speed of the application code. For example, you need to specify a maximum response time for all API calls or the number of records imported within a specific time range. After that, you can measure which parts of the application are too slow and need to be improved. After doing so, continue with the second tuning technique.
2. Use analyzer to find the real bottleneck
After you follow the first suggestion and confirm that some parts of your application do need improvement, ask yourself where to start?
You can solve this problem in two ways:
- You can take a look at your code, starting from what looks suspicious or where you think it may cause problems.
- You can also use analyzer to obtain detailed information about the behavior and performance of each part of the code.
The second method should always be followed.
The answer should be obvious. analyzer-based methods allow you to better understand the performance of your code and focus on the most critical part. If you have used analyzer before, you will be surprised by what part of the code causes performance problems. However, in many cases, your first guess will lead you to the wrong direction.
3. Create a performance test suite for the entire application
This is another general technique that helps you avoid many unexpected problems. These problems usually occur after performance improvement is deployed to the production environment. You should often define a performance test suite for testing the entire application and run it before and after you complete performance improvement.
These additional test runs will help you identify the functional and performance impact of the changes, and ensure that you do not release an update that has more disadvantages than the benefits. This is especially important if your task runs on multiple different parts of the application, such as the database or cache.
4. Solve the biggest bottleneck first
After creating a test suite and using analyzer to analyze the application, you have a list of problems that need to improve performance. This is good, but it still cannot answer the question from where you should start. You can start with something that can be done quickly or from the most important issue.
Of course, the former is very attractive, because it will soon produce results. Sometimes, you may need to convince other team members or your management that performance analysis is worthwhile.
But in general, I suggest starting with the most important performance issues. This will provide you with the greatest performance improvement, and you may only need to fix a few of these problems to solve your performance requirements.
After learning about general performance tuning techniques, let's take a closer look at some Java-specific tuning techniques.
5. Use StringBuilder to connect strings programmatically
There are many different connection string options in Java. For example, you can use a simple ++ or ++ =, StringBuffer, or StringBuilder.
So what method should you choose?
The answer depends on the code of the connection string. If you add new content to a string programmatically, for example, in a for loop, you should use StringBuilder. It is easier to use and provide better performance than StringBuffer. But remember that StringBuilder is different from StringBuffer. It is not thread-safe and may not be suitable for all use cases.
You only need to instantiate a new StringBuilder and call the append method to add a new part to the string. After adding all the parts, you can call the toString () method to retrieve the connection string.
The following code snippet shows a simple example. During each iteration, this loop converts I into a string and adds it to the space of StringBuilder sb, this code writes "this is test0123456789" to the log file.
StringBuilder sb = new StringBuilder(“This is a test”);for (int i=0; i<10; i++) { sb.append(i); sb.append(” “);}log.info(sb.toString());
As you can see in code snippets, you can provide the first element of a string for the constructor method. This creates a new StringBuilder that contains the provided string and 16 additional characters. When you add more characters to StringBuilder, JVM dynamically changes the size of StringBuilder.
If you already know how many characters your string contains, You can provide this number to different constructors to instantiate a StringBuilder with the defined capacity. This further improves its efficiency because it does not need to dynamically expand its capacity.
6. Use the + connection string in the Declaration
When you implement the first application in Java, someone may tell you that you should not use ++ to connect strings. This is correct if the string is connected in the application logic. The string is immutable, and the result of each string connection is stored in a New String object. This requires additional memory and reduces the application speed, especially when multiple strings are connected in a loop.
In these cases, you should follow tip 5 and use StringBuilder.
But if you just break a string into multiple lines to improve code readability, that's not the case.
Query q = em.createQuery(“SELECT a.id, a.firstName, a.lastName ”+ “FROM Author a ”+ “WHERE a.id = :id”);
In these cases, you should use a simple ++ to connect your string. The Java compiler will optimize it and execute the connection during compilation. Therefore, when running, the Code only uses one character and does not need to be connected.
7. Use Basic Data Types whenever possible
Another way to avoid overhead and improve application performance is to use raw data types instead of their packaging classes. Therefore, it is best to use int instead of Integer, or double instead of Double. This will allow JVM to store the value in the stack to reduce memory consumption and process it more effectively.
8. Avoid BigInteger and BigDecimal
Since we have discussed the data types, let's take a look at BigInteger and BigDecimal. Especially the latter, because of its high precision and popularity. But there is a price.
BigInteger and BigDecimal require more memory than simple long or double, and greatly reduce the computing speed. Therefore, if you need extra precision or your number exceeds a long range, you 'd better think twice. This may be the only thing you need to change in improving performance, especially when you are implementing a mathematical algorithm.
9. Check the current log level first
This suggestion is obvious, but unfortunately you will find that many codes ignore it. Check the current log level before creating a debug message.
Here are two examples to illustrate that you should not do this.
// don't do thislog.debug(“User [” + userName + “] called method X with [” + i + “]”);// or thislog.debug(String.format(“User [%s] called method X with [%d]”, userName, i));
In both cases, you will execute all the required steps to create log messages without knowing whether the log framework uses log messages. Check the current log level before creating a debugging message.
10. Use Apache Commons StringUtils. Replace to replace String. Replace
In general, the String. replace method works well and is very efficient, especially if you are using Java 9. However, if the application requires a lot of replacement operations and you have not updated to the latest Java version, it makes sense to check faster and more effective alternatives.
One candidate is the Apache Commons Lang's StringUtils. replace method. As described in his recent blog article, Lukas Eder is much larger than the String. replace method of Java 8.
It only requires a small change. You only need to add a Maven dependency to your application pom. xml for the Apache's Commons Lang project, and replace all the calls of the String. replace method with the StringUtils. replace method.
// replace thistest.replace(“test”, “simple test”);// with thisStringUtils.replace(test, “test”, “simple test”);
11. cache expensive resources, such as database connections
Caching is a popular solution to avoid repeated execution of expensive or frequently used code fragments. The general idea is simple: repeated use of these resources is much cheaper than creating a new resource again and again.
A typical example is to cache database connections in the pool. It takes time to create a new connection. If you reuse an existing connection, you can avoid this.
You can also find other examples in the Java language itself. For example, the valueOf method of the Integer class caches values between-128 and 127. You may say that creating a new integer is not too expensive, but it is often used. The most common value in cache provides performance benefits.
But when you consider caching, remember that cache implementation also produces overhead. You need to spend extra memory to store reusable resources. Therefore, you may need to manage your cache so that the resources can access or delete outdated resources.
Therefore, before you start caching any resources, make sure that they are frequently used.
Summary
As you can see, it is sometimes not necessary to do a lot of work to improve application performance. Most of the suggestions in this article can be applied to the Code with a little effort.
But the most important advice is usually unrelated to programming languages:
- Do not optimize it before you know it is necessary.
- Use analyzer to find the real bottleneck
- First, solve the biggest bottleneck