Java uses the mechanism of automatic garbage collection, and C + + is the mechanism of this garbage collection is highly unpredictable, that is, there is no way to explicitly control the garbage collection in Java. The recycling mechanism for Java garbage is a problem that is often asked during an interview. So what should we say if we have such a problem? By looking at a lot of blogs, I think I can answer them from the following points. 1. Understanding the meaning of garbage collection
In short, the meaning of garbage collection in Java is to reclaim heap memory that is not referenced and allocate storage space for new objects. The reason we want to study the garbage collection mechanism is that garbage collection is a costly task. If we understand the mechanism of garbage collection, we can in programming to avoid unnecessary garbage collection, so as to improve the efficiency of programming. 2. Commonly used garbage collection algorithms
The Java language Specification does not explicitly describe which garbage collection algorithm the JVM uses, but any garbage collection algorithm typically does 2 basic things: Discovering unwanted information objects, reclaiming the memory space occupied by unwanted objects, and making the space available for reuse by the program.
Most garbage collection algorithms use the concept of root set (root set), which is the collection of reference variables (including local variables, parameters, class variables) that are accessible to the executing Java program, and the program can use reference variables to access the object's properties and invoke the object's methods. Garbage collection first needs to determine what is accessible from the root and which are unreachable, and the objects from the root set are active objects that cannot be reclaimed as garbage, which also includes objects that are indirectly accessible from the root set. The root set is eligible for garbage collection through an object that cannot be reached by any path,
should be recycled. Here are a few common algorithms. (1) Reference counting method (Reference counting Collector)
Reference counting is the only method that does not use the root set for garbage collection, 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 you create an object each time and assign it to a variable, 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 out of scope (discarded by the object), the reference counter is reduced by 1, and once the reference counter is 0, the object satisfies the garbage collection condition.
The garbage collector based on reference counters runs faster and does not interrupt program execution for a long time, and it is appropriate to run the program in real time. However, the reference counter increases the overhead of program execution because each object assigns a new variable to the counter plus 1, and each time an existing object is scoped, the counter is reduced by 1.
One of the biggest problems with reference counting is that it doesn't solve the problem of circular reference counting. For instance,
Class example{
Object I=new object ();
.....
}
public class gc{public
static void Test () {
Example a=new Example ();
Public Example b=new Example ();
A.I=B.I;
B.I=A.I;
A=null;
B=null
}
}
Here A and B reference counts are not 0, but the objects they point to are all null. (2) Tracing algorithm (tracing Collector)
The tracing algorithm is proposed to solve the problem of reference counting method, which uses the concept of root set. the garbage collector based on the tracing algorithm begins scanning from the root set, identifying which objects can be reached, which objects are unreachable, and marking the accessible objects in some way, such as setting one or more bits for each accessible object. in the scanning identification process, garbage collection based on the tracing algorithm is also known as the tag and Purge (Mark-and-sweep) garbage collector.
(3) copying algorithm (coping Collector)
The proposed algorithm is designed to overcome the cost of the handle and to solve the garbage collection of heap fragments. It starts by dividing the heap into an object area and multiple free areas, the program allocates space for objects from the object area, and 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 scratch area (so that there is no idle interval between the active object's memory), So the free area becomes the object area, the original object area becomes the free area, the program will be in the new
Allocates memory in the object area. A typical garbage collection based on coping algorithm is the stop-and-copy algorithm, which divides the heap into the object area and the free region area, and the program suspends execution during the handoff between the object area and the free region.
(4) 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 latency of the program, which is why the coping algorithm is inefficient. In the program design, there is such a law: most objects exist in a relatively short time, a few of the existence of a long time. Therefore, the generation algorithm divides the heap into two or more, each of which is a generation of objects (generation). Because most objects exist for a relatively short time, the garbage collector collects the objects from the youngest child heap as the program discards unused objects. After the generational garbage collector runs, the last surviving object moves to the next highest-generation child heap, saving time because the older generation's child heap is not often recycled.
(5) Adaptive Algorithm (adaptive Collector)
In certain cases, some garbage collection algorithms are superior to other algorithms. The garbage collector based on the adaptive algorithm monitors the current heap usage and will select the appropriate algorithm for the garbage collector. 3. How to explicitly do garbage collection work. (1) System.GC () method
Using System.GC () can request Java garbage collection regardless of which garbage collection algorithm the JVM uses. There is a parameter on the command line-VERBOSEGC can view the heap memory used by Java, which is formatted as follows:
JAVA-VERBOSEGC Classfile
You can see an example:
Class TESTGC
{public
static void Main (string[] args)
{ new TESTGC (); System.GC (); System.runfinalization ();
}
}
In this example, a temporary object is created and no reference is directed to it. After compiling, execute the command: JAVA-VERBOSEGC TESTGC After the result is:
[Full GC 168k->97k (1984K), 0.0253873 secs]
The environment of the machine is, Windows JDK1.3.1 +, the data 168K and 97K before and after the GC respectively indicate the amount of memory used by all the surviving objects before and after the garbage collection, indicating that the 168k-97k=71k object capacity is recycled, The 1984K of data in parentheses is the total capacity of the heap memory, and the time required for collection is 0.0253873 seconds (this time varies at each execution). It should be noted that calling System.GC () is only a request (recommended). When the JVM accepts this message, it does not do garbage collection immediately, but simply weights several garbage collection algorithms that make garbage collection operations easy to occur, occur earlier, or recycle more. (2) Finalize () method
Before the JVM garbage collector collects an object, it is generally required that the program call the appropriate method to free the resource, but in the absence of a clear release of resources, Java provides a default mechanism to terminate the object's heart-releasing resources, which is finalize (). Its prototype is:
protected void Finalize () throws Throwable
After the Finalize () method returns, the object disappears and the garbage collection starts executing. The throws Throwable in the prototype indicates that it can throw any type of exception.
The reason for using Finalize () is that there is a special case that the garbage collector cannot handle. Assume that your object (not using the new method) obtains a "special" area of memory, since the garbage collector only knows the memory space that is shown to be allocated through new, it does not know how to release the "special" memory area, then Java allows a class to define a Finalize () method. Special areas such as:
1) It is possible to use a C-language approach when allocating memory, rather than the usual new approach to Java. This happens mainly in native method, for example, native methods calls the C + + approach malloc () function series to allocate storage space, but unless the free () function is invoked, the memory space will not be released, then May cause memory leaks. However, because the free () method is a function in C + +, it can be invoked locally in Finalize (). To free these "special" memory spaces.
2) or open file resources that are not part of the garbage collector's recycle scope.
In other words, the main purpose of finalize () is to free up some of the memory space created by other practices, as well as to do some cleanup work. Because in Java there is no such thing as a "destructor" or a similar concept, to do some sort of cleanup, you have to create a common way to perform cleanup, that is, the Finalize () method in the class override object. For example, suppose an object draws itself to the screen during the creation process, and it may never be cleaned up if it is not explicitly erased from the screen. If a wipe function is added to finalize (), when the GC is working, Finalize () is called and the image is erased. If the GC does not occur, then the image will be preserved all the time.
Emsp; Once the garbage collector is ready to release the storage space occupied by the object, it first invokes the Finalize () method to perform some necessary cleanup work. The memory space occupied by the object will be released only the next time the garbage collection action is taken.
In normal cleanup, to clear an object, the user of that object must invoke a purge method at the location where the cleanup is desired. This is slightly inconsistent with the concept of C + + destructor. In C + +, all objects are corrupted (cleared). Or in other words, all objects are "supposed" to be corrupted. If you create a C + + object as a local object, such as in the stack (which is not possible in Java, Java is in the heap), the cleanup or destruction work is done at the end of the scope that the end curly braces represents to create the object. If the object is created with new (similar to Java), the corresponding destructor is invoked when the programmer invokes the C + + DELETE command (Java does not have this command). If the programmer forgets, then the destructor will never be invoked, and we end up with a memory "vulnerability" and the other parts of the object will never be erased.
In contrast, Java does not allow us to create local (local) objects – use new anyway. In Java, however, there is no "delete" command to release objects, because the garbage collector helps us to automatically free up storage space. So if you stand in a simpler position, we can say that there is no destructor in Java because of the garbage collection mechanism. However, as you learn later, you will know that the existence of the garbage collector does not completely eliminate the need for destructors, or that you cannot eliminate the need for the mechanism represented by destructors (for the next paragraph.) In addition, the Finalize () function is invoked when the garbage collector is ready to release the storage space occupied by the object, and cannot directly call Finalize (), so try to avoid it. If you want to perform some sort of cleanup work other than freeing storage, you must still call a method in Java. It is equivalent to a C + + destructor, but it is not convenient.
All objects in C + + must be destroyed by using delete (), and the objects in Java are not always reclaimed by the garbage collector. In another word, 1 objects may not be garbage collected, 2 garbage collection is not equal to "destructor", and 3 garbage collection is only related to memory. In other words, not if an object is no longer being used, is it going to release the other objects contained in the object in Finalize ()? No. Because no matter how the object is created, the garbage collector is responsible for releasing the memory that those objects occupy.4. Conditions that trigger the main GC (garbage Collector)
The JVM has a high frequency of GC, but because the GC takes a very short time, it has little impact on the system. What is more noteworthy is the trigger condition of the primary GC, because it has an obvious effect on the system. In general, there are two conditions that trigger the primary GC:
1 The GC is invoked when the application is idle, that is, no application thread is running. Because the GC is in the lowest-priority thread, the GC thread is not invoked when the application is busy, except for the following conditions.
2 When the Java heap is low on memory, the GC is invoked. When the application thread is running and a new object is created during the run, if there is not enough memory space, the JVM is forced to call the GC thread to reclaim the memory for the new assignment. If the GC is not able to meet the requirements of memory allocation after the first time, the JVM will do two more GC for further attempt, if still unable to meet the requirements, the JVM will report "Out of Memory" error, the Java application will stop.
Because the main GC is determined by the JVM based on the system environment, and the system environment is constantly changing, the main GC runs with uncertainty and cannot predict when it will inevitably occur, but it can be determined that the main GC is repeated for a long-running application. 5. A few additions to garbage collection
After the above explanation, we can find that garbage collection has the following characteristics:
The unpredictability of garbage collection occurs: Because different garbage collection algorithms are implemented and different collection mechanisms are in place, it may be timed to occur, possibly when the system is idle CPU resources, and possibly the same as the original garbage collection, which occurs when memory consumption limits. This is related to the choice of the garbage collector and the specific settings. The accuracy of garbage collection: mainly includes two aspects: (a) The garbage collector can accurately mark the living object; (b) The garbage collector can pinpoint the referential relationship between objects. The former is a prerequisite for completely reclaiming all discarded objects, or it may cause a memory leak. The latter is the necessary condition to realize merging and copying algorithms. All unreachable objects can be reliably recycled, all objects can be reassigned, allowing object replication and object memory to shrink, effectively preventing memory fragmentation. There are many different kinds of garbage collectors, each with its own algorithm and performance, which stops the application when garbage collection starts, and when garbage collection starts, it allows the thread of the application to run, as well as garbage collection multithreading at the same time. The implementation of garbage collection has a very close relationship with the specific JVM and the memory model of the JVM. Different JVMs may take different garbage collections, and the JVM's memory model determines which types of garbage collection the JVM can take. The memory systems in the Hotspot series JVM are now designed with an advanced object-oriented framework that enables the most advanced collection of garbage collections in this series of JVMs. With the development of technology, modern garbage collection technology provides many optional garbage collectors, and can set different parameters when configuring each collector, which makes it possible to obtain optimal applicability according to different application environments. 6. Measures to reduce GC overhead
According to the above GC mechanism, the operation of the program will directly affect the system environment changes, thus affecting the GC trigger. If you do not design and encode the characteristics of GC, there will be a series of negative effects such as memory presence. To avoid these effects, the basic principle is to minimize garbage and reduce the cost of the GC process as much as possible. Specific measures include the following:
(1) Do not explicitly call System.GC ()
This function recommends that the JVM be the primary GC, although it is recommended rather than certain, but in many cases it triggers the primary GC, which increases the frequency of the primary GC, and increases the number of intermittent pauses.
(2) Minimizing the use of temporary objects
The temporary object becomes garbage after the function call is dropped, and the less temporary variable is the equivalent of reducing garbage generation, thus prolonging the occurrence of the second triggering condition mentioned above and reducing the chance of the primary GC.
(3) It is best to explicitly null an object when it is not in use
In general, NULL objects are treated as garbage, so it is more efficient for GC collectors to determine garbage by explicitly setting unused objects to null.
(4) Try to use StringBuffer instead of string to accumulate strings
Because string is a fixed-length string object, accumulating a string object is not amplified in a string object, but rather creates a new string object, such as STR5=STR1+STR2+STR3+STR4, that produces multiple garbage objects during execution. Because a new string object must be created for the secondary "+" operation, these transition objects are meaningless to the system and will only add more garbage. To avoid this situation, you can use StringBuffer to accumulate strings, because the StringBuffer is variable length, it expands on the original basis, does not produce intermediate objects.
(5) can use basic type such as Int,long, do not use Integer,long object
The base type variable consumes much less memory resources than the corresponding object, and if it is not necessary, it is best to use the base variable.
(6) Use of static object variables as little as possible
Static variables are global variables and are not reclaimed by GC, and they can occupy memory all the time.
(7) Time to create or delete dispersed objects
Focusing on a large number of new objects in a short time, especially large objects, can result in a sudden need for large amounts of memory, which, in the case of the JVM, can only be primary GC to reclaim memory or consolidate memory fragmentation, thereby increasing the frequency of the primary GC. The same is true for deleting objects centrally. It causes a sudden emergence of a large number of garbage objects, the inevitable reduction of free space, thereby greatly increasing the next time to create a new object to force the main GC opportunity.
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 = =) System.out.println ("created 47");
} protected void Finalize () {if (!gcrun) {Gcrun = true;
System.out.println ("Beginning to finalize" + created + "chairs have been created");
} if (i = =) {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"); } System.out.println ("All chairs have been created:/n" + "total created =" + chair.created + ", total final
ized = "+ 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 chair. Because the garbage collector may run at any time, we cannot know exactly when it will start. Therefore, the program uses a tag named Gcrun to indicate whether the garbage collector has started running. Using the second tag F,chair can tell main () that it should stop the object's generation. Both of these tags are set within finalize () and are used during garbage collection. The other two static variable –created and finalized– are used to track the number of objects created and the number of objects the garbage collector has finished finishing. Finally, each chair has its own (non-static) int I, so it can track what its specific number is. Chair with number 47 finishes the finishing work, the tag is set to true, and the Chair object is eventually created.