The pit caused by JDK1.6 in the production environment

This article is shared from Huawei Cloud Community " [High Concurrency] Remember a pit caused by JDK1.6 in the production environment! ", Author: Glacier.

Recently, a friend encountered a confusion: the program he wrote has no problems at all in the test environment, but memory overflow frequently occurs when it is sent to the production environment. This problem has been bothering him for more than a week.

Later, in the process of troubleshooting, I found that the JDK used by this little partner was still version 1.6. At first, I didn't think too much about it, and continued to check the code he wrote, but I didn't find any problems. But once the program in the production environment is started, it didn't take long for the JVM to throw a memory overflow exception.

This is strange, what's going on?

Add reasonable JVM parameters when starting the program, the problem still exists. . .

No way, continue to look at his code! Inadvertently, I found that in the code he wrote, the substring() method of the String class was used extensively to intercept the string. So, I followed the code in the JDK to check the parameters passed in.

This inadvertently clicked in to check, and found the problem! !

The pit of the String class in JDK1.6

After analysis, I found a big hole in the String class in JDK1.6! Why do you say it is a pit? It is because its substring() method will make people miserable! Not much to say, let's first look at the substring() method of the String class in JDK1.6.

public String substring(int bedinIndex, int endIndex){
    if(beginIndex < 0){
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if(endIndex > count){
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    if(beginIndex > endIndex){
          throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
    }
    return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value);
}

Next, let's take a look at a construction method of the String class in JDK1.6, as shown below.

String(int offset, int count, char[] value){
    this.value = value;
    this.offset = offset;
    this.count = count;
}

See, here, I believe that the careful friends have discovered the problem, and the culprit of the problem is the following line of code.

this.value = value;

In JDK1.6, when using the constructor of the String class to create a substring, it is not just a simple copy of the required object, but the entire value is quoted every time. If the original string is relatively large, even if the string is no longer used, the memory allocated by the string will not be released.  This is also the conclusion I came to after analyzing the code for a long time, it is really too bad! !

Now that the problem is found, let's fix it.

upgrade JDK

Since there is such a huge pit in the String class in JDK1.6, the most direct and effective way is to upgrade the JDK. So, I explained the situation to my friend and asked him to upgrade the JDK to JDK1.8.

Similarly, let's take a look at the substring() method of the String class in JDK1.8.

public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > value.length) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    int subLen = endIndex - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
        : new String(value, beginIndex, subLen);
}

In the substring() method of the String class in JDK1.8, the construction method of the String class is also called to generate a substring. Let's take a look at this construction method, as shown below.

public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count <= 0) {
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        if (offset <= value.length) {
            this.value = "".value;
            return;
        }
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

In JDK1.8, when we need a substring, substring generates a new string, which is constructed by the Arrays.copyOfRange function of the constructor. This is no problem.

Optimize JVM startup parameters

Here, in order to better improve the performance of the system, I also helped this little partner optimize the JVM startup parameters.

Authorized by my friends,  I briefly listed their business scale and server configuration: the entire system adopts a distributed architecture, and each business service in the architecture adopts a cluster deployment, with an average daily visit volume of hundreds of millions, an average daily transaction order of 50W~100W, and an order Each server node of the system is configured as 4-core 8G. Currently the JDK has been upgraded to version 1.8.

According to the above conditions, I give the parameter configuration after JVM tuning.

-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M

As for why the above JVM parameter configuration is given, I will write a separate article later to specifically analyze how to tune JVM parameters according to actual business scenarios.

After analyzing and solving the problem, the program of the little partner runs smoothly in the production environment, at least there is no memory overflow situation yet! !

in conclusion

If a relatively large object is created in the program, and we generate some other information based on this large object, at this time, we must release the reference relationship with this large object, otherwise, the hidden danger of memory overflow will be buried.

The goal of JVM optimization is to allocate and recycle objects in the new generation as much as possible, try not to let too many objects frequently enter the old generation, avoid frequent garbage collection of the old generation, and at the same time give the system sufficient memory size to avoid the new generation Frequent garbage collection.

Click to follow and learn about Huawei Cloud's fresh technologies for the first time~

 

It is infinitely faster than Protocol Buffers. After ten years of open source, Cap'n Proto 1.0 was finally released. The postdoctoral fellow of Huazhong University of Science and Technology reproduced the LK-99 magnetic levitation phenomenon. Loongson Zhongke successfully developed a new generation of processor Loongson 3A6000 miniblink version 108. The world's smallest Chromium core ChromeOS splits the browser and operating system into an independent 1TB solid-state drive on the Tesla China Mall, priced at 2,720 yuan Huawei officially released the security upgrade version of HarmonyOS 4, causing all Electron-based applications to freeze AWS will begin to support IPv4 public network addresses next year Official release of Nim v2.0, an imperative programming language
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4526289/blog/10092960