Java Memory leak issues

Source: Internet
Author: User

Issue background:
In the development of this issue, in order to the customer's API interface on a daily basis to send ordered data (order data volume is large, there are about 800 stores, on average each store about 100 orders per day about the data), the total data is about 100,000. This data we need to be sent to each other at a certain point in time every day.

Development Design Summary:
At design time we used an open source distributed Task Scheduler framework, Xxl-job, to manipulate our data sending tasks through a simple and straightforward web page.

Program outline:
1. Query to obtain all the store ID of the place order;
2. Cycle the store ID to obtain the order information of the store and send

The problem occurs:
During the development process, we are all in the test database. There are fewer stores and only dozens of of the order data. Successfully developed, put the program in the simulation of the real environment of the server, the first day of normal operation, in the evening before work also logged in Xxl-job control page to see all the normal, to this I thought this project is finished. Feel a lot of ease in a moment, home footsteps are a lot lighter.
After coming to work the next morning, I wanted to see if the program was running stably last night, ready to open the dispatch control page. However, when I enter the URL in the browser return, the page was loaded for 2 seconds, not out. Suddenly my heart is tight, sure enough the final page prompts me to "Cannot access this page."
By looking at the log of the server, the program reported a memory overflow error at 7:30 A.M.. At the same time also put my service program to stop.

Parsing the problem:
from the reported memory overflow error, we can clearly get the cause of the program to die, it is certain that my program in the process of running a large number of JVM-created heap memory, resulting.
So I Baidu a bit, the cause of memory overflow may be as follows:
1. The amount of data loaded in memory is too large, such as fetching too much data from the database at once;
2. The collection class has references to objects that are not emptied after use, so that the JVM cannot be reclaimed;
3. An object entity in the code that has a dead loop or loop that produces too many duplicates;
4. Bugs in the third-party software used;
5. Startup parameters The memory value setting is too small;
The first thought might be to increase the JVM's heap memory space, but this is not the root cause. The underlying problem is the code.
//Store order data at the time of shipment on demand

 list<map<string, object>> allorderedstore=allorderedstore (sysDate) ; for  (int  i = 0; i < allorderedstore.size (); I++) { String store_id  =allorderedstore.get (i). Get ("store_id"  =allorderedstore.get (i). Get ("Receive_date"  //  All stores ordering information  List<map<string, object>> storeorderdetails = Jdbcsourcedao.getorderitemlist (sysdate,store_id,receive_date); Storeorder (Store_id,receive_date, storeorderdetails);}  

Review my Code, I follow the store to take data to send one by part, so I loop create a lot of list objects, used to store the store's order data, perhaps I was too wrong to create, but also did not empty in a timely manner, resulting in the GC recovery mechanism is not timely recovery, resulting in memory overflow it?
Garbage collection mechanism:
In life, the so-called rubbish refers to what we do not need, not in use of goods, these items crowding out the space we need,
And let's have the idea of discarding it to free up more space.
There are two very important benchmarks in this understanding of rubbish, one is the object and the other is space.
1. Heap Memory:
In Java, the object corresponds to "objects", and space is "Java Heap memory" (created at JVM startup, mainly used to maintain runtime data);
Here again, stack memory: A reference variable that is used to store some basic types of variables and objects.
2. Rubbish:
Garbage in Java memory refers to an object that is no longer alive. There are two main ways to determine whether an object survives:
A. Reference count:
Assign a reference counter to each object you create, and when the object is referenced, the counter is incremented by 1, and the counter minus 1 when the reference is removed, so repeat. When the counter value is 0 o'clock, the object "dead" is determined. However, there is a serious problem with this scheme-it is impossible to monitor the "cyclic application", and when two objects are applied to each other, even if it is not referenced by any other object, the reference count of the two can never be zero, so it will survive forever.

B. Accessibility analysis:
Think of all referenced objects as a tree, starting from GC Roots, the root node of the tree, and continually traversing the objects that are "accessible" to all the objects that are connected (referenced), which are surviving, and those that cannot be traversed are not "accessible" and are dead.
Reference, OBJECT5,OBJECT6 and object7 are unreachable objects and are considered "dead states" and should be reclaimed by the garbage collector.

GC Roots:
First of all, we literally see that the GC Roots this root with "Roots" is a complex number, we can not be difficult to guess that the root object is more than the unique, it is said to refer to the object "tree" there are many trees. The main root objects are four kinds:
The object referenced in the virtual machine stack (the local variable table in the frame stack).
The object referenced by the static property in the method area.
The object referenced by the constant in the method area.
The object that is referenced by JNI in the local method stack.

3. Garbage collection:
Through the above brief introduction, already knew that those objects are rubbish, now I look for the tool to sweep the rubbish.
Such as:
Figure 1
The green block represents the available space, Gray indicates the space occupied by the surviving object, and black indicates the space occupied by the garbage object.

3 kinds of algorithms for garbage collection:
A. Tag cleanup:
The first step, the so-called "tag" is the use of accessibility to traverse the heap memory, the "Survival" Object and "garbage" objects tagged, resulting in 1;
The second step, since the "garbage" has been marked, then we go through again, all the "garbage" object occupied by the space directly emptied.
The results are as follows:
Figure 2

This is a markup cleanup, simple and convenient, but prone to generating memory fragmentation.
B. Mark Collation:
To compensate for the memory fragmentation of the tag cleanup algorithm, we do a cleanup before the garbage objects are cleaned up. Move all the surviving objects together so that the garbage is cleared and no memory fragmentation occurs.
The results are as follows:

Tag cleanup and tag grooming do not have too much action on the surviving object, so these two methods are suitable for scenarios where there are many surviving objects and less garbage objects.
C. Copy Empty
This method is simple and rough, directly divides the memory into two parts, for a period of time only allow allocation in one piece of memory, when the memory is allocated, then garbage collection, all the surviving objects are copied to another piece of memory, the current memory is emptied directly.
The results are as follows:

Start by using only the upper portion of the memory until the memory is used, garbage collection, all the surviving objects to the lower part, and the upper part of the empty.
It's not easy to fragment, it's simply rude, but it means that you can only use a portion of your memory for a period of time, more than that memory, which means the frequent duplication of memory in the heap is emptied.
Because this algorithm needs to copy the surviving objects from the workspace to the storage area, this scheme is suitable for few surviving objects and more garbage.

Know that there are three kinds of algorithms can be garbage collection, then Java is the choice of the algorithm for garbage collection?
Because the above three algorithms have their own scenarios, so Java should also be divided into scenes to select the recovery algorithm.
However, tag cleanup is prone to memory fragmentation, which is why it should not be chosen in general, and only the markup collation and replication cleanup is left.
tags organize scenes that are suitable for many surviving objects, and copy and clean up scenes that are suitable for fewer surviving objects. So when does the Java program survive many objects, when there are fewer objects to live on, and those objects are always alive?

Return to our program, there will be a lot of local variables in the general program, and relatively few global variables. As a result, there will be a lot of new surviving objects when the program starts running, but most of them will not be long enough to be unreachable, quickly die, and others will survive for a relatively long time, while others, such as static files, These objects are characterized by no need for garbage collection.

Based on these features, predecessors have made a simple division of Java's heap memory space.
New generation: Objects that have just been created are uniformly placed in an area. (Fewer surviving objects, more garbage) suitable for copy emptying algorithm
Old age: An object that survives for some time and is uniformly placed in the area. (More survival objects, less garbage) suitable for labeling algorithm
Meta-space: the uniformly placed area of an object that is permanently present.

Labeling is better understood, but the copy emptying algorithm, due to the memory space involved in the division, so the relative understanding of the laborious point. The following is an in-depth exploration of the copy-emptying algorithm.
In the memory space to divide the most people think of is half-points, we put the new generation of memory space by 1:1 for the division

Using only half of the memory at a time, when the half is full, the garbage is collected, the surviving objects are copied directly to the other half of the memory, and the current half of the memory is emptied.
The flaw of this division is equivalent to only half the available memory, for the next generation, the new object is constantly being created, it is likely to be full of Eden memory and the memory will have to be garbage collection, it is obvious that continuous garbage collection work, but the impact of the normal program operation, not worth the candle.

There is too little Eden memory for the original pattern diagram, and there is more survivor memory space, so let's increase the ratio of Eden to 90% of Eden space. Such as:

Initially used in 9 of the memory area, when the 9 is nearly full, perform a copy collection, the 9 still live objects to the 1 zone, and empty the 9 zone.
This seems to be better than the above method, but it has a more serious problem.
When we copy the 9-zone surviving objects to the 1 zone, the ratio of memory space is relatively large, so it is likely that the 1 zones will not be able to reach the surviving objects from the 9-zone, so we have to move the objects to the old age area. And this means that there may be a part of the not-so-old 9-zone object that has been placed in the old-age area because of the 1-zone, and it is conceivable that this undermines the rules of the old-age area. Or, to a certain extent, old age areas are not necessarily all old age objects.
So how can we move the older objects to the old-age area?

That being the case, then we are going to be in a region (Survivorb) to store the surviving objects that may be put into the old age area, and if an object survives in that area for a certain number of times (usually 15 times), then we think this is an old age object, when we put it into the old age area.
The partition diagram is as follows:


At this point back to the question, because I was in a short period of time to create a large number of objects occupying large memory space, and the stack frame of this method can not be recycled (the local variable table is not reused in the operation); so I just need to manually empty after object creation and then call the GC. The code is as follows:
Storeorderdetails.clear ();
System.GC ();

This method temporarily solves my memory leak problem.

Java Memory leak issues

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.