The Java heap is a run-time data area in which instances (objects) of the class allocate space. The Java Virtual machine (JVM) heap stores all objects created by running applications, which are established through directives such as new, NewArray, Anewarray, and Multianewarray, but they do not require program code to be explicitly released. In general, the heap is responsible for garbage collection, although the JVM specification does not require special garbage collection techniques or even garbage collection at all, but because of the limited memory, the JVM has a heap managed by garbage collection when implemented. Garbage collection is a dynamic storage management technology, which automatically frees objects that are no longer referenced by the program, and implements the function of automatic resource recovery according to the specific garbage collection algorithm.
The meaning of garbage collection
In C + +, the memory occupied by an object is occupied until the end of the program and cannot be assigned to other objects until it is explicitly released, whereas in Java the memory becomes garbage when there is no object reference to the memory originally assigned to an object. A system-level thread of the JVM automatically frees the block of memory. Garbage collection means that the object that the program no longer needs is "useless information," and that information is discarded. When an object is no longer referenced, the memory reclaims the space it occupies so that the space is later used by the new object. In fact, in addition to releasing useless objects, garbage collection can also erase memory-logged fragments. The memory is fragmented because the object being created and the garbage collector frees up the memory space that the discarded objects occupy. Fragmentation is a free memory hole between the blocks of memory allocated to an object. Defragmentation moves the occupied heap memory to one end of the heap, and the JVM allocates the compiled memory to the new object.
Garbage collection can automatically free up memory space and reduce the burden of programming. This gives Java virtual machines some advantages. First, it can make programming more efficient. In the absence of a garbage collection mechanism, it may take a lot of time to solve a hard-to-understand memory problem. When programming in the Java language, the garbage collection mechanism can greatly shorten the time. Second, it protects the integrity of the program, and garbage collection is an important part of the Java language Security strategy.
One potential drawback of garbage collection is that its overhead affects program performance. The Java Virtual machine must trace the objects that are useful in the running program and eventually release the useless objects. This process takes the processor's time. Secondly, the incompleteness of garbage collection algorithm, some garbage collection algorithms used earlier can not guarantee that 100% collected all the discarded memory. Of course, with the continuous improvement of garbage collection algorithm and the efficiency of software and hardware running, these problems can be solved.
Algorithm analysis of garbage collection
The Java language Specification does not explicitly describe what garbage collection algorithm the JVM uses, but any garbage collection algorithm typically does 2 basic things: (1) Discovers useless information objects, (2) reclaims the memory space occupied by the useless objects so that the space can be reused by the program.
Most garbage collection algorithms use the concept of root set (root set), which is a collection of reference variables (including local variables, parameters, class variables) that are accessible by a Java program that is executing, and the program can use reference variables to access the properties of the object and methods of invoking the object. Garbage collection preferences need to determine which ones are accessible from the root and which are unreachable, objects that can be reached from the root set are active objects, and they cannot be recycled as garbage, which also includes objects that are indirectly accessible from the root set. The root set, which is unreachable by any path, is eligible for garbage collection and should be recycled. Here are a few common algorithms.
1. Reference counting method (Reference counting Collector)
Reference counting is the only method of garbage collection that does not use the root set, which uses reference counters to differentiate between surviving objects and objects that are no longer in use. In general, each object in the heap corresponds to a reference counter. When an object is created and assigned to a variable each time, the reference counter is set to 1. When an object is assigned to any variable, the reference counter is incremented by 1 each time the object is scoped (the object is discarded), the reference counter is reduced by 1, and once the reference counter is 0, the object satisfies the garbage collection condition.
A garbage collector based on a reference counter runs faster and does not interrupt program execution for long periods of time, and it is appropriate to run programs in real time. However, the reference counter increases the cost of executing the program because each time the object is assigned to a new variable, the counter adds 1, and each time the existing object is scoped, the counter is reduced by 1.
2. Tracing algorithm (tracing Collector)
The tracing algorithm is proposed to solve the problem of the reference counting method, which uses the concept of the root set. The garbage collector based on the tracing algorithm starts scanning from the root set to identify which objects are available, which objects are unreachable, and to mark objects in some way, such as setting one or more bits for each object that can be reached. During the scan recognition process, garbage collection based on the tracing algorithm is also known as the Mark and Purge (mark-and-sweep) garbage collector.
3. Compacting algorithm (compacting Collector)
To solve the problem of heap fragmentation, garbage collection based on tracing absorbs the idea of the compacting algorithm, in which the algorithm moves all objects to one end of the heap, and the other end of the heap becomes an adjacent free memory area, and the collector updates all references to all objects it moves. This allows these references to recognize the original object in the new location. In the implementation of the collector based on the compacting algorithm, the handle and the handle table are generally added.
4. Copying algorithm (coping Collector)
The algorithm is proposed to overcome the overhead of the handle and to solve the garbage collection of heap fragments. It begins by dividing the heap into an object face and multiple free polygons, the program allocates space for the object from the object surface, when the object is full, garbage collection based on the coping algorithm scans the active object from the root set and copies each active object to the free surface (so that there is no free hole between the memory occupied by the active object), The idle face becomes the object face, the original object face becomes the idle surface, and the program allocates memory in the new object face.
A typical garbage collection based on coping algorithm is the stop-and-copy algorithm, which divides the heap into object and idle area polygons, and the program suspends execution during the switching between the object surface and the idle area.
5. Generation algorithm (generational Collector)
One drawback of the stop-and-copy garbage collector is that the collector must replicate all active objects, which increases the program wait time, which is why the coping algorithm is inefficient. In the program design there is such a law: most objects exist for a short time, a few of the existence of a long time. Therefore, the generation algorithm divides the heap into two or more, each sub-heap as the object's generation (generation). Because most objects exist for a shorter time, the garbage collector collects these objects from the youngest child heap as the program discards objects that are not used. After the generational garbage collector runs, the last surviving object is moved to the next highest generation sub-heap, saving time because the old generation of sub-heaps is not often recycled.
6. Adaptive algorithm (Adaptive Collector)
In certain cases, some garbage collection algorithms are better than other algorithms. The garbage collector based on the adaptive algorithm monitors the usage of the current heap and will select the appropriate algorithm for the garbage collector. Perspective Java Garbage Collection
1. Command line parameter perspective garbage collector run
2. Use System.GC () to request Java garbage collection regardless of which garbage collection algorithm the JVM is using. There is a parameter in the command line-VERBOSEGC can view the heap memory used by Java, which is in the following format:
JAVA-VERBOSEGC Classfile
You can look at an example:
Class TESTGC
{
public static void Main (string[] args)
{
New TESTGC ();
System.GC ();
System.runfinalization ();
}
}
In this example, a new object is created, because it is not used, so the object quickly becomes accessible, after the program compiles, executes the command: JAVA-VERBOSEGC TESTGC After the result is:
[Full GC 168k->97k (1984K), 0.0253873 secs]
The environment for the machine is, Windows + JDK1.3.1, data 168K and 97K before and after the arrows represent the amount of memory used by all surviving objects before and after garbage collection GC, indicating that the 168k-97k=71k object capacity is recycled. The data in parentheses is 1984K to the total capacity of the heap memory, and the time required for collection is 0.0253873 seconds (this time will vary at each execution).
2. Finalize method to view the operation of garbage collector
Before the JVM garbage collector collects an object, it is generally required that the program call the appropriate method to dispose of the resource, but without explicitly releasing the resource, Java provides a default mechanism to terminate the object's heart release resource, which is finalize (). Its prototype is:
protected void Finalize () throws Throwable
After the Finalize () method returns, the object disappears and garbage collection begins execution. The throws Throwable in the prototype indicates that it can throw any type of exception.
The reason to use Finalize () is that there are times when you need to take a different approach to Java's common approach, by allocating memory to do something with C-style. This can be done primarily through "intrinsic methods", which are a way to invoke non-Java methods from Java. C and C + + are the only languages currently supported by native methods. But because they can invoke subroutines written in other languages, they are able to invoke anything effectively. Within non-Java code, you might be able to call the malloc () series of C, which allocates storage space. and unless free () is called, storage space is not freed, causing a memory "vulnerability" to occur. Of course, free () is a C and C + + function, so we need to call it in an intrinsic method inside Finalize (). This means that we cannot use Finalize () too much, and it is not an ideal place to do normal cleanup work.
In normal cleanup, to clear an object, the user of that object must invoke a purge method at the point where it is expected to be cleared. This is somewhat inconsistent with the concept of C + + "sabotage". In C + +, all objects are destroyed (cleared). Or, in other words, all objects "should" be destroyed. If you create a C + + object as a local object, such as in the stack (which is not possible in Java), the cleanup or destruction will be done at the end of the scope of the object that the "closing curly brace" represents. If the object is created with new (similar to Java), then when the programmer calls the C + + DELETE command (Java does not have this command), the corresponding destroy is invoked. If the programmer forgets, then never call the destruction, we will end up with a memory "vulnerability", also including the other parts of the object will never be erased.
Instead, Java does not allow us to create local (local) objects-in any case, using new. In Java, however, there is no "delete" command to dispose of objects, because the garbage collector helps us to automatically free up storage space. So if we stand in a relatively simplified position, we can say that there is a garbage collection mechanism, so Java does not have a destruction device. However, with further study, you will know that the existence of the garbage collector does not completely eliminate the need for the destruction, or the need to eliminate the kind of mechanism that the device represents (and definitely not directly call Finalize (), so try to avoid using it). If you want to perform some sort of cleanup work other than freeing the storage space, you still have to call one of the methods in Java. It is equivalent to C + + 's destruction, but not the latter convenience.
The following example shows you the process of garbage collection and summarizes the previous statements.
Class Chair {
static Boolean gcrun = false;
static Boolean f = false;
static int created = 0;
static int finalized = 0;
int i;
Chair () {
i = ++created;
if (created = = 47)
System.out.println ("Created 47");
}
protected void Finalize () {
if (!gcrun) {
Gcrun = true;
System.out.println ("Beginning to finalize after" + created + "chairs has been created");
}
if (i = = 47) {
System.out.println ("Finalizing Chair #47," + "Setting flag to stop Chair creation");
F = true;
}
finalized++;
If (finalized >= created)
System.out.println ("All" + finalized + "finalized");
}
}
public class Garbage {
public static void Main (string[] args) {
if (Args.length = = 0) {
System.err.println ("Usage: \ n" + "java garbage before\n or:\n" + "java Garbage after");
Return
}
while (! CHAIR.F) {
New Chair ();
New String ("to take up space");
}
System.out.println ("After all chairs has been created:\n" + "total created =" + chair.created +
", Total finalized =" + chair.finalized);
if (Args[0].equals ("before")) {
SYSTEM.OUT.PRINTLN ("GC ():");
System.GC ();
System.out.println ("Runfinalization ():");
System.runfinalization ();
}
System.out.println ("bye!");
if (Args[0].equals ("after"))
System.runfinalizersonexit (TRUE);
}
}
The above program creates many chair objects, and at some point after the garbage collector starts running, the program stops creating the chair. Because the garbage collector may run at any time, we don't know exactly when it starts. Therefore, the program uses a tag called Gcrun to indicate whether the garbage collector has started running. Using the second tag, F,chair can tell main () that it should stop generating the object. Both of these tokens are set internally in Finalize () and are tuned for garbage collection. The other two static variables--created and finalized--are used to track the number of objects that have been created and the number of objects that the garbage collector has finished finishing. Finally, each chair has its own (non-static) int I, so it can track how much it is specific. Chair with number 47 completes the finishing touches, the tag is set to true to end the Chair object creation process.
A few additions to garbage collection
After the above description, you can find that garbage collection has the following characteristics:
(1) The unpredictable nature of garbage collection: Due to the implementation of different garbage collection algorithms and the use of different collection mechanisms, it may be timed to occur, it is possible to occur when the system is idle CPU resources, it may be the same as the original garbage collection, wait until memory consumption limit occurs, This is related to the choice of the garbage collector and the specific settings.
(2) The accuracy of garbage collection: mainly includes 2 aspects: (a) The garbage collector can accurately mark the living objects; (b) The garbage collector is able to pinpoint the referential relationships between objects. The former is a precondition for completely reclaiming all discarded objects, or it may cause a memory leak. The latter is necessary for the realization of algorithms such as merging and copying. All unreachable objects can be reliably recycled, all objects can be reassigned, objects are copied and object memory is shrunk, which effectively prevents fragmentation of memory.
(3) There are many different kinds of garbage collectors, each with its algorithm and its performance, both stopping the application when garbage collection starts, and allowing the application's thread to run when garbage collection starts, as well as the garbage collection multithreading at the same time.
(4) The implementation of garbage collection is closely related to the specific JVM and the JVM's memory model. Different JVMs may have different garbage collections, and the JVM's memory model determines what types of garbage collection the JVM can take. The memory systems in the HotSpot family of JVMs are now designed with an advanced object-oriented framework, allowing the JVM to use state-of-the-art garbage collection.
(5) With the development of technology, modern garbage collection technology provides many optional garbage collectors, and in the configuration of each collector can also set different parameters, which makes it possible to obtain the best application performance according to the different applications environment.
In view of the above characteristics, we should pay attention to when using:
(1) Do not attempt to assume that garbage collection occurs at any time, all of which are unknown. For example, a temporary object in a method becomes a useless object when the method call is complete, and its memory can be freed at this time.
(2) Java provides a number of classes that deal with garbage collection, and provides a way to enforce garbage collection-calling System.GC (), but this is also an indeterminate approach. Java does not guarantee that each call to this method will be able to start garbage collection, it will only issue to the JVM such a request, whether or not to actually perform garbage collection, everything is unknown.
(3) Pick a garbage collector that suits you. In general, if your system does not have special and demanding performance requirements, you can use the JVM's default options. Otherwise, you might consider using a targeted garbage collector, such as an incremental collector, which is more suitable for systems with higher real-time requirements. The system has a high configuration, there are more idle resources, you can consider using the parallel tag/purge collector.
(4) The key is also difficult to grasp the problem is the memory leak. Good programming habits and rigorous programming attitude is always the most important, do not let your own a small error caused a large memory leak.
(5) Release the reference of the useless object as soon as possible. Most programmers use temporary variables when the reference variable is automatically set to null after exiting the active domain (scope), implies that the garbage collector collects the object, and must be aware that the referenced object is listening, and if so, remove the listener and then assign a null value.
Conclusion
In general, Java developers can not focus on the allocation of heap memory and garbage collection in the JVM, but fully understanding the Java feature allows us to use resources more efficiently. Also note that the Finalize () method is the default mechanism for Java, and sometimes you can write your own Finalize method to ensure explicit release of object resources.
Java garbage Collection