问题
I am trying to do some memory analysis using visualvm. I have written a basic code that runs an infinite loop to add objects to List.
package home.always.learning.java;
import java.util.ArrayList;
import java.util.List;
public class Heaper {
private static List<PersonDetails> listObj = new ArrayList<PersonDetails>();
private static final String nameConst = "Tarun Trehan";
public static void main(String[] args)throws Exception{
personListCreation();
}
public static void personListCreation() throws Exception
{
int i = 0;
while(true)
{
System.out.println("Looping to create person list...");
i++;
listObj.add(new PersonDetails(nameConst+i));
//Thread.sleep(1000L);
}
}
}
As expected, memory shoots up and is visible in visualvm 1st snapshot attached i.e. Memory_Shoots.JPG.
However, if i remove the following comment from the code and allow the program to sleep for 1 second; the result is different:
Thread.sleep(1000L);
The memory increases but then stabilizes and it goes on. Please refer 2nd snapshot attached i.e. Memory_Stabilizes.JPG
I am unable to understand this behavior? Can you please provide your inputs.
回答1:
Looking at a slightly modified version of the code (fixed number of iterations, added a 5s pause after start to allow my IDE to connect to visualvm, removed the system.out.print for speed, etc) it seems your culprit is garbage collection:
With 100L sleep: (ran for 5:18)
With 10L sleep: (ran for 5:01)
With 2L sleep: (ran for 4:57)
With 1L sleep: (ran for 6:36)
With 0L sleep: (ran for 0:23)
So basically what we find is that the used heap will rise slowly until the Eden space is filled (causing an allocation failure), moving the older members of eden (almost all of them, looking at the space usage) to survivor 0/1, and some of those to the old gen. The difference between sleep and no sleep may very well be a difference between the relative frequencies of minor collections and major collections.
回答2:
There are a couple things that are worth thinking about:
- How big are these PersonDetail objects?
- How much memory is required to create a PersonDetail object, that isn't part of the object?
This second value can be a lot of thing. The array list will produce some garbage every so often. The process of creating the string "nameConst+i" will result in some garbage objects.
Suppose the answer is that a PersonDetail is small but it takes a medium amount of memory to make one. Then the JVM is going to have a bunch of trash to throw away (garbage collect) for every PersonDetail you make. As you create PersonDetails the garbage will pile up and eventually the JVM will collect it. The garbage collection step will find a lot of free memory since most of the allocations are short lived objects. This will could result in a graph like the one in your second picture, a saw tooth, where the memory is used then lots of garbage is collected.
Now imagine that you create a bunch of objects quickly (without the sleep statement). Now the total memory used is going to go up quickly both through garbage and through the objects you are holding in the list. As you get to the max memory the garbage collections will have to happen more frequently. Kind of like the top graph.
I am not sure that is what is happening, but one thing you can do to look at it is to look at the sampling in VisualVM and see how many objects are created by class, and more importantly how much memory they take up. Compare the amount used by the PersonDetails to the other stuff that is just garbage to be cleaned when needed.
来源:https://stackoverflow.com/questions/17160643/java-memory-behavior-different-with-thread-sleep