“This is the 28th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

1. JVM garbage collection mechanism and common algorithms

In theory, Sun only defines the garbage collection mechanism rules, not the implementation algorithm, so different virtual machines from different vendors use different algorithms.

Before collecting objects, the Garbage Collector must find them. How to find and locate them? Common search algorithms are as follows:

1) Reference counter algorithm (obsolete)

The reference counter algorithm sets a counter for each object, which is +1 when the object is referenced somewhere, -1 when the reference is invalid, and 0 when the object is considered unused and “garbage” by the JVM.

Reference counter is simple to implement and high efficiency. But it does not solve the problem of circular reference asking (object A refers to object B, and object B refers to object A, but

Objects A and B are no longer referenced by any other objects), and each increment and decrement of the counter caused A lot of overhead, so this algorithm was discontinued after JDK1.1.

2) Root search algorithm (using)

The root search algorithm uses some “GC Roots” objects as the starting point, and searches down from these nodes. The path through the search becomes the reference chain

(Reference Chain), when an object is not connected by GC Roots’ Reference Chain, the object is not available.

GC Roots objects include:

A) objects referenced in the virtual machine stack (local variable table in the stack frame).

B) objects referenced by class static properties in the method area.

C) Objects referenced by constants in the method area.

D) Objects referenced by JNI (Native method) in the Native method stack.

After finding useless objects through the above algorithm, it is the recycling process. The recycling algorithm is as follows:

1) Mark-sweep (the algorithm used by DVM)

The mark-clear algorithm consists of two phases: “mark” and “clear”. In the marking phase, all objects to be reclaimed are identified and marked. The clear phase follows the mark phase, purging objects that the mark phase determined were not available. The mark-sweep algorithm is a basic collection algorithm. The efficiency of the mark and sweep phase is not high, and the large amount of discontinuous space will be generated after the sweep, so when the program needs to allocate large memory objects, it may not be able to find enough continuous space.

2) Copying algorithms

The replication algorithm divides memory into two equal pieces, uses one piece each time, and when garbage collection is made, copies the surviving objects onto the other piece, then cleans up the entire memory. The replication algorithm is simple to implement and runs efficiently. However, only half of the replication algorithm can be used at a time, resulting in low memory utilization. Current JVMS collect the new generation by copying, and since most objects in the new generation (98%) die overnight, the memory ratio is not 1:1(about 8:1).

3) Mark-Compact algorithm

The mark-collation algorithm is the same as the mark-clean algorithm, but instead of copying the live object to another block of memory, the mark-collation algorithm moves the live object to one end of memory, and then directly reclaims the memory beyond the boundary. The mark-collation algorithm improves memory utilization, and it is suitable for collecting objects with long lifetime.

4) Generational Collection

Generational collection divides memory into new generation and old generation according to the survival time of objects. According to the survival characteristics of objects in each generation, different garbage collection algorithms are used in each generation.

The new generation adopts copy algorithm, while the old generation adopts mark-collation algorithm. The implementation of the garbage algorithm involves a great deal of procedural detail, and different virtual machine platforms implement it in different ways.

 

2. Talk about the MEMORY structure and allocation of the JVM

A)Java memory model

The Java virtual machine divides the memory under its jurisdiction into roughly three logical parts: Method Area, Java stack, and Java heap.

Method areas are statically allocated. The compiler binds variables to a storage location and these bindings do not change at run time.

Constant pools, named constants, String constants, and static variables from source code are stored in the method area.

Java Stack is a logical concept characterized by lifO. The space of a stack may be continuous or discontinuous.

The most typical Stack application is method invocation. Each time the Java VIRTUAL machine calls a method, a method frame is created. When the method exits, the corresponding method frame is popped. The data stored in the stack is also determined at runtime.

Java Heap allocation means a memory management model in which storage space is allocated and reclaimed at run time in an arbitrary order. The size, amount, and lifetime of data stored in the heap are often undetermined at compile time. Memory for Java objects is always allocated in the heap. We write code every day and use the MEMORY of the JVM every day.

B) Java memory allocation

1. Base data types are allocated directly in stack space;

2. The method’s formal parameters are allocated directly in the stack space and reclaimed from the stack space after the method call is completed;

3, reference data type, need to use new to create, both stack space allocation of an address space, and heap space allocation of object class variables;

Allocate an address space in the stack space and point to the object area of the heap space. When the method is called, it will be recycled from the stack space.

5. When the local variable new comes out, space is allocated between stack space and heap space. When the local variable life cycle ends, the stack space is immediately reclaimed, and the heap space area is waiting for GC collection.

6. The actual parameters passed in during method call are first allocated in stack space and released from stack space after method call is completed;

String constants are allocated in the DATA section and this is allocated in the heap.

The array allocates the name of the array in the stack space and the actual size of the array in the heap space.

3. What are the reference types in Java

There are four levels of references to objects in Java, from highest to lowest: strong reference, soft reference, weak reference, and virtual reference.

StrongReference

So without going into that, strong references are what we use every day when we write code. If an object is strongly referenced, the garbage collector will never reclaim it. When running out of memory, the Java virtual machine would rather throw outofMemoryErrors to abort the program than randomly recycle objects with strong references to resolve the memory problem.

Java objects are placed in the heap, where objects are strongly reachable, soft reachable, weakly reachable, virtually reachable, and unreachable. The order of application is strong, soft, weak and virtual. Which reachable object an object belongs to is determined by its strongest reference. The following code:

String abc=new String("abc"); //1 SoftReference<String> softRef=new SoftReference<String>(abc); //2 WeakReference<String> weakRef = new WeakReference<String>(abc); //3 abc=null; //4 softRef.clear(); / / 5Copy the code

The first line creates an object of content “ABC” in the heap and establishes a strong reference to ABC to that object, which is strongly reachable.

The second and third lines establish soft and weak references to objects in the heap, respectively. At this point, the ABC object in the heap already has three references and is clearly still strongly reachable.

After the fourth line, objects in the heap are no longer strongly reachable and become soft reachable.

The fifth line becomes weakly reachable after execution.

SoftReference

If an object has only soft references, the garbage collector will not reclaim it if there is enough memory, and will reclaim the memory of these objects if there is not. As long as the garbage collector does not collect it, the object can be used by the program. Soft references can be used to implement memory sensitive caching.

A soft reference can be used in conjunction with a ReferenceQueue (ReferenceQueue), and if the object referenced by the soft reference is garbage collected, the Java virtual machine adds the soft reference to the ReferenceQueue associated with it.

Soft references are primarily used for memory sensitive caches. All soft references are cleared before the JVM reports that it is out of memory, so that the GC can collect soft reachable objects, possibly resolving the memory crunch problem and avoiding memory overruns. When it is collected depends on the GC algorithm and the amount of memory available at GC runtime. When the GC decides to collect soft references, the following procedure is performed, for example with softRef above:

1 First set softRef’s referent (ABC) to null and no longer reference the New String(” ABC “) object in the heap.

2 Set the new String(” ABC “) object in the heap to finalizable.

3 When the Finalize () method of a New String(” ABC “) object in the heap is run and the memory used by that object is freed, softRef is added to its ReferenceQueue(if any).

Note: Soft and weak ReferenceQueue references are optional, but virtual references must be present.

Objects referenced by Soft Reference will not be deleted even if there is no Direct Reference. The SoftReference is cleared only when the JVM has insufficient memory and no Direct Reference is available. The SoftReference is used for object cache design. SoftReference caches objects without causing outofMemoryerrors.

WeakReference

If an object has only weak references, then the class is unnecessary because the GC will kill the object whenever it is scanned. The difference between weak and soft references is that objects with only weak references have a shorter lifetime. When the garbage collector thread scans the memory area under its control, once it finds an object with only weak references, it reclaims its memory regardless of whether the current memory space is sufficient or not. However, because the garbage collector is a low-priority thread, objects that have only weak references are not necessarily found quickly.

Weak references can be used in conjunction with a ReferenceQueue (ReferenceQueue), and if the object referenced by a weak reference is garbage collected, the Java virtual machine adds the weak reference to the ReferenceQueue associated with it.

Virtual Reference

A “virtual reference” is, as the name implies, a virtual reference. Unlike the other references, a virtual reference does not determine the lifetime of an object. If one is right

Like holding only a virtual reference, it is as likely to be garbage collected at any time as having no reference at all. Virtual references are mainly used to track the activity of objects being garbage collected.

One difference between a virtual reference and a soft or weak reference is that a virtual reference must be used in conjunction with a ReferenceQueue. When the garbage collector is about to reclaim an object and finds that it has a virtual reference, it adds the virtual reference to the reference queue associated with it before reclaiming the object’s memory. A program can determine whether a referenced object is about to be garbage collected by determining whether a virtual reference has been added to the reference queue. If a program finds that a virtual reference has been added to the reference queue, it can take the necessary action before the memory of the referenced object is reclaimed.

When a virtual reference is created, the get method will always return null. As you can see from the source code, the virtual reference method will write the referenced object into the referent, but the GET method will return null. Let’s look at the interaction with gc and see what it does.

1 Instead of setting the referent to NULL, set the heap new String(” ABC “) object to finalizable.

2 Unlike soft and weak references, the PhantomRefrence object is first added to its ReferenceQueue. The virtual reachable objects are then released.

What’s the difference between a heap and a stack

The difference between a heap and a stack is described in the following ways.

(1) Application method

Stack: Automatically assigned by the system. For example, declare a local variable int b in a function; The system automatically creates space in the stack for B.

Heap: requires the programmer to apply and specify the size, in C malloc function, for Java requires manual new Object().

(2) Response of the system after application

Stack: If the remaining space of the stack is larger than the requested space, the system provides memory for the program. Otherwise, an exception is reported indicating stack overflow.

Heap: The first thing you should know is that the operating system has a linked list of free memory addresses, and when the system receives an application request,

The list is traversed looking for the first heap node that has more space than the requested space, and the node is removed from the free list and allocated to the program. In addition, since the size of the found heap may not be exactly the size of the requested heap, the system will automatically put the extra heap back into the free list.

(3) Limit of application size

Stack: THE stack is a data structure that extends to a lower address. It is a contiguous area of memory. The address at the top of the stack and the maximum size of the stack are specified by the system. Under WINDOWS, the stack size is 2M (or 1M). If the stack size exceeds the available space, overflow will be prompted. Therefore, less space can be obtained from the stack.

Heap: a data structure that expands to a higher address. It is a discontinuous area of memory. This is because the system uses a linked list to store free memory addresses, which is naturally discontinuous, and the traversal direction of the list is from low address to high address. The size of the heap is limited by the amount of virtual memory available in the computer system. Thus, the heap is more flexible and larger.

(4) Comparison of application efficiency

Stack: The system automatically assigns data to the stack with high speed. But programmers have no control.

Heap: memory allocated by new, usually slow and prone to memory fragmentation, but most convenient to use.

(5) The contents stored in heap and stack

Stack: When a function is called, the address of the next instruction in the main function (the next executable statement of the function calling statement) is first pushed, followed by the arguments of the function. In most C compilers, arguments are pushed from right to left, followed by local variables in the function. Note that static variables are not pushed.

When this function call ends, the local variable is first off the stack, then the parameter, and finally the top pointer points to the original address, which is the next instruction in the main function, and the program continues to run from this point.

Heap: The size of the heap that is typically placed in one byte at the head of the heap. The specific contents of the heap are arranged by the programmer.

(6) Differences at the level of data structure

Then there are stacks and heaps in terms of data structures, which are different concepts. The heap refers to a data structure of a priority queue, with the first element having the highest priority; A stack is essentially a data or data structure that satisfies the “in, out” nature. Although the terms stack are called together, they are quite different, but for historical reasons.

(7) Expand knowledge (application of stack in Java)

The stack and heap are both places where Java stores data in Ram. Unlike C++, Java automatically manages stacks and heaps, and programmers cannot set up stacks or heaps directly.

2). The advantage of the stack is that access is faster than the heap, second only to the registers directly located in the CPU. However, the disadvantage is that the size and lifetime of the data in the stack must be determined, which lacks flexibility. In addition, stack data can be shared, as shown in Point 3. The advantage of the heap is that the memory size can be allocated dynamically, the lifetime of the heap does not have to be told to the compiler in advance, and the Java garbage collector automatically collects the data that is no longer used. The downside is that access is slow because memory is allocated dynamically at run time.

3). There are two data types in Java.

There are 8 primitive types (int, short, long, byte, float, double, Boolean, char) for primitive types (note that there is no primitive type for string). This type is defined by something like int a = 3; long b = 255L; Automatic variables: they are created only when they are defined, and the storage space they occupy is reclaimed by the system when the function that defined them returns. The allocation and reclamation of the storage space for these variables is done automatically by the system. . It is important to note that automatic variables hold literals, not instances of classes, i.e. not references to classes. There is no class. Int a = 3; Here a is a reference to an int, to the literal 3. The data for these literals, because of their size and lifetime (they are fixed in a block whose field value disappears when the block exits), is kept on the stack for speed reasons.

In addition, one of the most important features of the stack is that data can be shared within the stack. Suppose we also define int a = 3; Int b = 3;

Int a = 3; First it creates a reference to a on the stack, then looks for an address with a literal value of 3. If it doesn’t find one, it creates an address with the literal value of 3, and then points a to the address of 3. Int b = 3; After creating a reference variable to B, we point b directly to the address of 3, since we already have a literal of 3 on the stack. So we have both a and B pointing to 3 at the same time.

In particular, this literal reference is different from that of a class object. If one object reference variable modifies the internal state of that object, the other object reference variable immediately reflects that change. In contrast, modifying the value of a reference to a literal does not cause the value of another reference to the literal to change as well. In the example above, after we define the values of a and b,

To make a = 4; So b is not going to be equal to 4, it’s still going to be equal to 3. Inside the compiler, a=4 is encountered; “, it will search the stack again to see if there is a literal of 4, if not, the address to store the value of 4; If it already exists, point A directly to that address. So a change in the value of A doesn’t affect the value of B.

The other is wrapping class data, such as Integer, String, Double, etc. around the corresponding basic data type. The class data is all in the heap, and Java uses the new() statement to explicitly tell the compiler that it is created dynamically at run time on demand, so it is more flexible, but takes more time.

Each JVM thread has its own private stack space, which is created as the thread is created. The Java stack stores frames, while the Java stack is different from the C stack, which only stores local variables, return values, and call methods. Direct push and pop frames are not allowed because frames may be allocated by heap, so Java’s stack does not need to allocate contiguous memory. The Java Heap is shared by all threads. The heap holds all runtime data, all object instances and arrays, and the Heap is created when the JVM starts.

5).string is a special wrapper class data. String STR = new String(” ABC “); String STR = “ABC”; (For comparison, before JDK 5.0, you’ve never seen Integer I = 3; Because classes and literals are not generic, except for strings. In JDK 5.0, such expressions are allowed! Because the compiler does Integer I = new Integer(3) conversion in the background). The former is the formal class creation process, that is, in Java, everything is an object and an object is an instance of a class, all created in the form of new(). So why in String STR = “ABC”; Does not create instances through new() violate the above principle? Not really.

5.1). Internal workings of String STR = “ABC”. (1) define a reference variable to the String class named STR: String STR;

(2) Search the stack for an address containing the value “ABC”. If not, create an address containing the literal value “ABC”. Then create a new String object O and point the String value of O to this address. If you already have an address with the value “ABC”, look for the object O and return the address of O.

(3) set STR to the address of object o.

It is worth noting that String values are stored directly in the String class. But like String STR = “ABC”; In this case, the string value holds a reference to the data on the stack!

To better illustrate this problem, we can verify it with the following code. String str1 = “abc”;

String str2 = "abc";

System.out.println(str1==str2);      //true
Copy the code

Note that we don’t use str1.equals(str2) here; Because this compares whether the values of the two strings are equal. ==, which, according to the JDK, returns true only if both references refer to the same object. And what we’re looking at here is whether str1 and str2 both refer to the same object.

It turns out that the JVM created two references str1 and str2, but only one object, and both references refer to that object. Let’s go one step further and change the above code to:

String str1 = "abc"; String str2 = "abc";

str1 = "bcd";

System.out.println(str1 + "," + str2);      //bcd, abc System.out.println(str1==str2);     //false
Copy the code

That is, the assignment change causes the class object reference to change, and str1 points to another new object! Str2 still points to the original object. In the example above, when we changed the value of str1 to “BCD”, the JVM found that there was no address on the stack for that value, opened that address, and created a new object whose string value pointed to that address.

In fact, the String class is designed to be immutable. If you want to change its value, you can, but the JVM quietly creates a new object at run time based on the new value, and then returns the address of that object to the reference to the original class. This creation process, while fully automated, takes more time. In the time sensitive environment, it will have some adverse effects.

Modify the original code again:

String str1 = "abc"; String str2 = "abc"; str1 = "bcd"; String str3 = str1;

System.out.println(str3);         //bcd String str4 = "bcd";

System.out.println(str1 == str4);    //true  
Copy the code

The reference to str3 points directly to the object pointed to by str1 (note that str3 does not create a new object). After str1 has changed its value, create a String reference to STR4 that points to the new object created because str1 changed its value. As you can see, str4 does not create any new objects this time, again sharing data on the stack.

Let’s continue with the following code.

String str1 = new String("abc"); String str2 = "abc";

System.out.println(str1==str2);      //false
Copy the code

Two references are created. Two objects are created. Two references refer to two different objects.

Any new object created with new() is created in the heap, and its string is stored separately, even if it is the same as the data on the stack.

6). The value of the data type wrapper class cannot be modified. Not only is the value of the String class immutable, but all data type wrapper classes cannot change their internal values.

7). Conclusions and Suggestions:

(1) we are using things like String STR = “ABC”; When we define a class in the format of, we always assume that we have created an object STR of class String. Worry about traps! The object may not have been created! The only thing you can be sure of is that a reference to the String class is created. Whether this reference refers to a new object depends on the context, unless you explicitly create a new object through the new() method. Therefore, it is more accurate to say that we created a reference variable STR to an object of the String class, which refers to some String class with the value “ABC”. Being aware of this can be very helpful in eliminating hard-to-find bugs in your programs.

String STR = “ABC”; “Can speed up the program somewhat, because the JVM automatically determines whether new objects need to be created based on the actual data in the stack. For String STR = new String(” ABC “); The code creates new objects in the heap regardless of whether the string values are equal or whether it is necessary to create new objects, thus increasing the program’s burden. This is supposed to be the meta schema idea, but it is not clear whether the JDK’s internal implementation applies this schema here.

Equals () = equals(); When testing whether references to two wrapper classes refer to the same object, use ==.

(4) Because of the immutable nature of String, we should consider using The StringBuffer class when we need to change the value of a String variable frequently. If Java cannot successfully allocate heap space, an OutOfMemoryError is thrown.

5. Explain the usage of stack, heap, and method area in memory

Usually we define a variable of a basic data type, a reference to an object, and the field saving of a function call all use the stack space in the JVM; Objects created by the new keyword and constructor are placed in the heap space, which is the main area managed by the garbage collector. Since garbage collectors now use generational collection algorithms, the heap space can also be divided into new generation and old generation. To be more specific, it can be Eden, Survivor (also From Survivor and To Survivor), and Tenured; The method area and heap are areas of memory shared by individual threads that store information about classes that have been loaded by the JVM, constants, static variables, code compiled by the JIT compiler, and so on. Literals in the program such as the directly written 100, “hello”, and constants are placed in the constant pool, which is part of the method area. The stack space is the fastest to operate but the stack is small. Usually a large number of objects are placed in the heap space. Both stack and heap sizes can be adjusted by the JVM’s startup parameters.

String str = new String("hello");
Copy the code

In the above statement, the variable STR is placed on the stack, the string object created with new is placed on the heap, and the “hello” literal is placed in the method area.