JDK, JRE, JVM

JavaSE: Standard edition of the Java platform, which provides the foundation for Java EE and Java ME.

JDK: Java development kit. The JDK is a superset of the JRE and contains everything in the JRE, as well as the compiler and debugger tools needed to develop the program.

JRE: Java SE runtime environment that provides libraries, Java virtual machines, and other components to run programs written in the Java programming language. Major class libraries, including: program deployment and distribution, user interface utility classes, inheritance libraries, other base libraries, language and tool base libraries.

JVM: Java virtual machine responsible for hardware and operating system independence, compiled execution code (bytecode), and platform security of the JavaSE platform.

The FULL name of JVM is Java Virtual Machine, also known as Java Virtual Machine. It recognizes files with the.class suffix and can parse its instructions, eventually calling functions on the operating system to do what we want.

A Java program first needs to be compiled by javac into a.class file, which the JVM loads into the method area, and the execution engine executes the bytecode. When executed, it is translated into operating system-specific functions. The JVM exists as a translation of.class files, entering bytecode and calling operating system functions.

The process is as follows: Java file > compiler > bytecode >JVM > machine code.

Note: The JVM is a virtualized operating system, so the most important thing to do besides virtualize instructions is to virtualize memory, which is the memory region of the JVM.

Java program execution process

CPU + cache + memory execution engine + operand stack + heapCopy the code

The memory region of the JVM

In the process of executing Java programs, the Java virtual machine will divide the memory it manages into several different data regions. Analyzing the JVM memory structure mainly refers to analyzing the JVM runtime data storage regions.

The runtime data area of the JVM mainly includes: heap, stack, method area, program counter, etc.

According to the relationship between threads, it can be divided into: thread private and thread shared.

There is also direct memory, which is not part of the runtime data area but is used frequently. You can think of it as other memory on an operating system that is not virtualized (for example, if the operating system has 8 gigabytes of memory and the JVM virtualizes 3 gigabytes of memory, then there is 5 gigabytes of memory left, and the JVM uses 5 gigabytes of memory with some tools, this portion of memory is called direct memory).

Other common structure drawings:

Thread private

Program counter

The Program Counter Register can be seen as a line number indicator of the bytecode executed by the current thread, pointing to the next instruction code to be executed, which is read by the execution engine. Rather, a thread executes by changing the value of the current thread’s counter through the bytecode interpreter to fetch the next bytecode instruction that needs to be executed, thus ensuring that the thread executes correctly.

A program counter is a small memory space that is used to record the addresses of bytecodes executed by individual threads. For example, branches, loops, jumps, exceptions, thread recovery, and so on all depend on the counter.

Because Java is a multithreaded language, when the number of threads executing exceeds the number of CPU cores, threads compete for CPU resources based on time slice polling. If a thread runs out of time or is robbed of CPU resources prematurely for other reasons, the exiting thread needs a separate program counter to record a running instruction.

Because the JVM is a virtual machine, it has a complete set of instructions and execution process, so when running Java methods, you need to use program counters (which record the address or line number of the bytecode execution). If you encounter native methods, this method is not executed by the JVM. This is because there is also a program counter at the operating system level that records the address of the execution of the native code, so the value of the program counter in the JVM is null (Undefined) when the native method is executed. The program counter is also the only memory area in the JVM that is not OOM(OutOfMemory).

Therefore, there are two main reasons why program counters are needed in the JVM:

  • Java is multithreaded, which means thread switching

    In order to ensure that the thread can be restored to the correct execution position after the switch (context switch), each thread has an independent program counter, the counters of each thread do not affect each other, stored independently. That is, the program counter is thread private memory.

  • Ensure that the program is running properly in multi-threaded situations

For chestnut, if you are the interviewer is the interview, the interview process suddenly say the boss to give you a telephone interview after the dinner, the interview this behavior is suspended at this time, when you have to interview after the call, so at this point you can’t ask a question before it again, but then, answer the phone before then asked.

Java virtual machine stack

FILO (first in, last out) is a data structure in which items are arranged in order, and items can only be inserted and deleted at one end (called the top of the stack). The stacks in the JVM include the Java virtual machine stack and the Native method stack. The difference between the two is that the Java virtual machine stack serves the Java methods executed by the JVM, while the Native method stack serves the Native methods used by the JVM.

The virtual machine stack is used to store data, instructions, and return addresses required by the current thread’s method while the JVM is running.

The virtual stack is thread-based: even if you only have a main() method, it runs thread-like. In the life cycle of a thread, the data involved in the calculation is frequently pushed on and off the stack, and the life cycle of a stack is the same as that of a thread.

The default vm stack size is 1 MB. You can adjust the vm stack size using Xss, for example, -xss256K. You can see the default values for some common platforms in the official documentation. As follows:

How are the data, instructions, and return addresses required by the current thread to run the method stored?

Each program is a private thread in the process of execution. When the thread runs, each method being executed is packaged into a stack frame and merged into the stack. Once the method completes the corresponding call, the stack is removed.

A stack frame generally contains four areas :(local variable table, operand stack, dynamic link, return address)

Local variables table: as the name implies is a table of local variables, used to store our local variables. First of all, it is a 32-bit length, which mainly stores the eight basic data types of Java. Generally, it can be stored in 32 bits, and if it is 64 bits, it can use high and low bits to occupy two data types. If it is some local objects, such as our Object Object, We just need to store a reference address to it. (Basic data type, object reference, returnAddress type)

Operation data stack: The operand stack, which holds the operands that our method executes, is a stack, a first-in, last-out stack, and the operand stack, which is used to operate on, can be any Java data type, so we know that when a method starts, the operand stack is empty, The operand stack is always running on/off the stack.

Dynamic concatenation: Each stack frame contains a reference to a method in the runtime constant pool that the stack frame attributes. This reference is held to support dynamic concatenation during method calls. A large number of symbolic references exist in the constant pool of the Class file, and the method invocation instructions in the bytecode take symbolic references to methods in the constant pool as arguments. Some of these symbolic references are converted to direct references during class loading or the first time they are used, which is called static resolution. The other part is converted to a direct reference during each run, which is called the dynamic join.

Return address: After a method has been executed, there are two ways to exit the method. The first method is that the execution engine encounters a bytecode instruction returned by any method. In this case, a return value may be passed to the upper level method caller (the method calling the current method is called the caller). Whether there is a return value and the type of return value will depend on which method return instruction is encountered. This exit Method is called Normal Method Invocation Completion. Another way out is, encountered in the process of method execution is unusual, and the exception no are processed in the method, whether exception is generated in the Java virtual machine or code used in athrow bytecode instruction exception, as long as there is no search in this method the exception table to match the exception handler, will cause the method exits, This exit is called the Abnormal Method Invocation Completion. A method that exits with an exception completion exit does not return any value for all its calls. Either way, before a method exits, it needs to return to the point where the method was called in order for the program to continue executing. When a method returns, it may need to store some information in the stack frame to help restore the execution state of its upper methods. In general, when a method exits normally, the value of the caller’s PC counter can be used as the return address, and it is likely to be stored in the stack frame. When a method exits, the return address is determined by the exception handler, and this information is generally not stored in the stack frame. Method of process in fact is equal to the current frame out of the stack, so exit may perform operations are: to restore the upper method local variables and the operand stack, the return value (if any) in the call stack frame of the operand stack, call PC counter value is to point to the method call instruction behind an instruction, etc.

Of course, the memory in the virtual stack is not infinite. It has a size limit, which is 1M by default. If we keep adding frames to the virtual machine stack but do not remove them, the virtual machine stack will burst, which is a StackOverflowError.

Methods in Java are given the following procedure for execution in the virtual machine stack

Public class JavaStack {public void getMoney(int money) {money = money + 100; } public static void main(String[] args) { JavaStack javaStack = new JavaStack(); javaStack.getMoney(10000); }}Copy the code

The bytecode information of the getMoney method is as follows: javap -c xxxx.class

    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: bipush        100
         3: iadd
         4: istore_1
         5: return
      LineNumberTable:
        start Length Slot Name Signature
         0      6     0   this    ...
         0      6     1   money   ...
Copy the code

For the getMoney method, it’s just a stack frame

  1. 0: ILOAD_1: local variable table of subscript 1 int is pushed

  2. 1: bipush 100: pushes a byte constant onto the stack

  3. 3: iadd: Unstack the data of the two ints at the top of the stack, add, and push the result onto the stack

  4. 4: istore_1: Stores the top int, “_1”, into the local variable “1”

Attached: Java bytecode instructions

Local method stack

The local method stack is similar to the Java virtual machine stack, which is used to manage calls to Java functions, and the local method stack, which is used to manage calls to local methods. But native methods are not implemented in Java, but in C (such as the Object.hashcode method).

The native method stack is an area very similar to the virtual machine stack that serves native methods. You can even think of the virtual machine stack and the local method stack as the same area.

It is not mandated by the VIRTUAL machine specification and can be implemented on all versions of the virtual machine. HotSpot directly blends the local method stack with the virtual machine stack.

Threads share

Methods area

Method areas are areas of runtime memory that can be shared by threads. It stores structural information for each class, such as the Runtime Constant Pool, field and method data, bytecode content for constructors and common methods, and special methods for class, instance, and interface initialization.

The method area is a “logical partition” of memory by the JVM. Prior to JDK1.7 and earlier, many developers used the term “persistent generation” because in the HotSpot virtual machine, designers used persistent generation to implement the method area of the JVM specification. In JDK1.8 and later, meta-spaces were used to implement method areas.

When the JVM executes a class, it must be loaded first. When a class is loaded (loading, validating, preparing, parsing, and initializing), the JVM first loads a class file. The class file contains information about the class version, fields, methods, and interfaces, as well as the Constant Pool Table. Used to hold various literal and symbolic references generated during compilation.

Constant pools versus runtime constant pools

When a class is loaded into memory, the JVM stores the contents of the class file’s constant pool into the runtime constant pool. During the parsing phase, the JVM replaces symbolic references with direct references (the index value of the object). For example, a string constant in a class file is stored in the class file constant pool. After the JVM loads the class, the JVM puts the string constant into the runtime constant pool and, during the parsing phase, specifies the index value of the string object.

The runtime constant pool is shared globally. Multiple classes share the same runtime constant pool. Only one copy of the same string in the constant pool will exist in the class file.

Constant pools have many concepts, including runtime constant pools, class constant pools, and string constant pools (I’ll cover them in more detail later, but you can skip to the end). The virtual machine specification only defines the above areas as method areas, not virtual machine vendor implementations. Strictly speaking, the static constant pool holds string literals, symbol references, and class and method information, and the runtime constant pool holds runtime direct references.

Run-time constant pooling is the transfer of symbolic reference values from the static constant pool to the run-time constant pool after the class is loaded. After the class is parsed, symbolic references are replaced with direct references.

After JDK1.7, the runtime constant pool was moved to heap memory, which is the physical space and still logically belongs to the method area (which is the logical partition).

dimension

The method area, like the heap space, is also a shared memory area, so the method area is shared by threads. If two threads are trying to access the same class information in the method area, and the class has not yet been loaded into the JVM, only one thread is allowed to load it, and the other thread must wait.

In the HotSpot virtual machine, the pool of static variables and runtime constants for the persistent generation has been moved to the heap in the Java7 release, the rest is stored in the JVM’s non-heap memory, and the Java8 release has removed the persistent generation implemented in the method area. The previous persistent generation is replaced with class metadata, which is stored in local memory.

Why does Java8 use meta-spaces instead of persistent generations, and what are the benefits of doing so?

The official explanation:

The removal of persistent generations is an effort to merge HotSpot JVM with JRockit VM, as JRockit does not have persistent generations and therefore does not need to be configured.

Memory often enough or permanent generation of memory, an exception is thrown. Java lang. OutOfMemoryError: PermGen. This is because in JDK1.7, the size of the specified PermGen area is 8M. Since metadata information of the classes in PermGen may be collected during each FullGC, the recovery rate is always low, and the results are not satisfactory.

It is also difficult to determine how much space to allocate for PermGen. The size of PermSize depends on many factors, such as the total number of classes loaded by the JVM, the size of the constant pool, and the size of the methods.

Meta space size parameters:

Jdk1.7 and earlier (initial and maximum) : -xx :PermSize; – XX: MaxPermSize; After jdk1.8 (initial and maximum) : -xx :MetaspaceSize; -xx :MaxMetaspaceSize jdk1.8

The heap

The heap is the largest area of memory on the JVM, where almost all of the objects we request are stored. When we say garbage collection, the object of operation is the heap.

Heap space is usually claimed at startup, but not always used. The heap is typically set up to be scalable. As objects are created frequently, the heap space becomes more and more occupied, and objects that are no longer in use need to be irregularly reclaimed. This is called Garbage Collection (GC) in Java.

When an object is created, is it allocated on the heap or on the stack? This has to do with two things: the type of the object and its location in the Java class.

Java objects can be divided into basic data types and ordinary objects.

  • For normal objects, the JVM creates the object on the heap first, and then uses references to it elsewhere. For example, store this reference in a local variable table in the virtual machine stack.

  • For basic data types (byte, short, int, long, float, double, char), there are two cases.

    • When you declare an object of primitive data type in the method body, it is allocated directly on the stack.
    • In other cases, it’s all on the heap.

Heap size parameter:

-xms: minimum heap value. -xmx: indicates the maximum value of the heap. -XMN: Cenozoic size; – XX: NewSize; Cenozoic minimum value; -xx :MaxNewSize: indicates the maximum value in the new generation. For example – Xmx256m

Direct memory (off-heap memory)

Direct memory is more scientifically known as out-of-heap memory.

When the JVM is running, it requests large chunks of heap memory from the operating system for data storage. There is also the virtual machine stack, the local method stack, and the program counter, called the stack area. The remaining memory of the operating system is also known as out-of-heap memory.

It is not part of the run-time data area of the virtual machine, nor is it an area of memory defined in the Java Virtual Machine specification; If NIO is used, this area is frequently used and can be referenced and manipulated directly within the Java heap using directByteBuffer objects.

This memory is not limited by the Java heap size, but is limited by the total native memory, which can be set by -xx :MaxDirectMemorySize (the default is the same as the maximum heap memory), so an OOM exception will occur.

In-depth understanding of the runtime data area

It’s a bunch of conceptual stuff, some of it’s a little hard to understand, so keep going.

JVM memory processing process

Analyze an example of code running in JVM memory processing throughout the process as follows:

  1. The JVM requests memory from the operating system

    The FIRST step for the JVM is to request memory from the operating system using configuration parameters or default configuration parameters. The JVM then allocates the starting and ending addresses of memory segments to the JVM, which then allocates them internally.

  2. The JVM allocates the heap, stack, and method area memory size based on configuration parameters. We set this to -xMS30m -XMx30m -xSS1m-xx :MaxMetaspaceSize=30m

  3. Class loading

    The class is put into the method area, and static variables and constants in the class are also put into the method area.

  4. Execute methods and create objects

    Start the main thread, execute the main method, and start executing the first line of code. A Teacher object is created in the heap and the object reference T1 is stored on the stack. When the new keyword is encountered in subsequent code, a Teacher object is created and the object reference is stored on the stack.

The JVM starts on the operating system, allocates memory, initializes the runtime data area, loads the classes into the method area, and finally executes the methods. The execution and exit of a method are represented in memory as the loading and unloading of frames in the virtual machine stack. Meanwhile, objects created during the execution of a method (new) are generally placed in the heap, and the last objects in the heap also need to be garbage collected.

The heap space is divided into generations

The heap was divided into The Cenozoic and the old (Tenured) ages, and the Cenozoic was further divided into Eden and Survivor zones, with Survivor composed of From Survivor and To Survivor. The usual GC happens in the heap.

What is the GC

Garbage Collection (GC) is an automated Garbage Collection mechanism in the JVM that we generally don’t care about. The important area for GC in the JVM is the heap space. We can also actively initiate it in additional ways, such as system.gc (), actively.

JHSDB visualization tool

JHSDB is an out-of-process debugging tool based on a service proxy implementation. A service agent is a set of apis in the HotSpot VIRTUAL machine that map the running information of the Java virtual machine, mainly based on the Java language implementation.

Start the

JDK8

When starting JHSDB, you must copy sawindbg. DLL (usually in the JDK directory) to the corresponding jre directory (note that there is usually a JRE directory in the same directory after installing JDK8 on Windows). Then go to F:\softwares\jdk8\lib and execute java-cp.\ sa-jdi.jar sun.jvm.hotspot.hsdb. As follows:

JDK9 and later versions

Going to the bin directory of the JDK, we can start it from the command line using JHSDB HSDB.

Add XX:+UseConcMarkSweepGC and -xx: -usecompressedoops to the VM parameters of the previous code to specify the garbage collector.

The GC was called manually in the previous main method

JHSDB operation

Because the JVM starts a process, you need to use the command JPS to find the corresponding process, as shown below

Then view it in JHSDB by process ID

Viewing heap parameters

In the figure above, you can see a comparison of the heap parameters during the actual JVM startup. You can see that the generation division in the heap space is continuous without memory compression being enabled.

View objects

Here you can see that all objects in the JVM are class-based objects

We find the object in the JVMObject class as follows:

Gc was manually called 15 times in the previous code (more on that later in the GC section), so object T1 is in the old age, and object T2 is in the Eden region of the new generation.

Viewing stack Information

View the stack information of the main method

From the above you can verify the stack memory, and also verify that the virtual machine stack and the local method stack are implemented as one in Hotspot.

Understand virtual machine memory optimization techniques – data sharing between stack frames

In the general model, the memory area of the two different stack frames is independent, but most JVMS implement optimizations such that the two stack frames overlap (mainly in the case of passing parameters in methods). Overlap the operand stack of the lower frame with the local variables of the upper frame. This saves space and, more importantly, allows you to share some of the data directly when making method calls without having to copy and pass additional arguments.

Stack information after the code is executed

Understanding memory overflow

Out Of Memory (OOM) refers to the Memory that cannot be reclaimed or too much Memory is used in an application system, so that the program uses more Memory than the maximum available Memory. Can’t run the program, the system will prompt out of memory, sometimes software will automatically shut down, restart the computer or software after the release of memory and can normal operation of the software, and the system configuration, data flow, the user code and other reasons lead to memory overflow error, even if the user to perform a task will not be able to avoid. — Baidu Baike

By the way, let’s talk about the difference between memory overflow and memory leak.

  • Memory overflow: The memory required by the program to run is greater than the memory provided.
  • Memory leak: Memory is allocated while the program is running, but the object is not reclaimed after the program completes execution and remains in a persistent state, such as in useThreadLocalAfter noremove.
  • The relationship between the two: Too many memory leaks will result in memory overflow. How to understand? Multi-thread execution of the same memory leak program, that is, after taking up too much memory, beyond the specified size of memory, the natural overflow.

Stack overflow

We default the stack memory size to 1m: -xss1M. The following code demonstrates stack overflow

The HotSpot version has a fixed stack size and does not support extension.

Java. Lang. StackOverflowError method invocation is difficult to appear commonly, if appear may be infinite recursion.

The takeaway from the virtual stack is that the execution of a method is inherently slower than a loop that implements the same function, so both recursion and non-recursion (loop implementation) make sense in tree traversal. Recursive code is concise, while non-recursive code is complex but fast.

OutOfMemoryError: The machine does not have enough memory because threads are being created and the JVM is requesting stack memory. (Generally can not demonstrate, demonstrate the machine also died)

Note also that there is no way for the JVM to limit the size of the stack area, because the JVM has threads running continuously, so only the size of a single virtual machine stack is limited.

Stack overflow

Direct memory overflow: request memory space, exceeding the maximum heap memory space. If there is a memory overflow, increase the -xms, -xmx parameters.

Set VM Args to -xMS30m -xmx30m -xx :+PrintGCDetails

There is also an exception that you may encounter at work: GC overhead Limit Exceeded, as follows

This kind of circumstance is not direct memory overflow, means that the object in the memory is must survive, which reaches a certain amount will overflow, is just like water cup water, first is empty, when meet water dissatisfaction will directly, but if you didn’t pay attention to, when the water is full, this time to overflow, this process is similar to the memory. But if you take a few sips when it’s full, the cup can be refilled, a process that logically can be understood as GC tuning.

But why overflow when you have GC tuning? The official reason:

This exception is thrown when more than 98% of the time is spent GC and less than 2% of the heap is reclaimed.

How to solve it?

  1. Then you should check the JVM’s heap parameter Settings against the machine’s memory to see if there is any room to tweak.
  2. See if your project has a lot of dead loops or code that uses a lot of memory, and optimize the code.
  3. Increase heap memory.

Method area overflow

Method area overflow can occur in the following two cases:

  1. Runtime constant pool overflow

  2. The Class object saved in the method area was not reclaimed in time or the Class information took up more memory than we configured. The Class can be recycled only if it is possible, but there are still some parameters that can be controlled.

    • All instances of the class have been reclaimed, that is, there are no instances of the class in the heap.
    • The ClassLoader that loaded the class has been reclaimed.
    • The java.lang.Class object corresponding to this Class is not referenced anywhere, and the methods of this Class cannot be accessed anywhere through reflection.

CGLIB is a powerful, high-performance, high-quality code-generating library that extends Java classes and implements Java interfaces at run time. At the bottom of the CGLIB package is the ability to transform bytecode and generate new classes by using ASM, a small and fast bytecode processing framework. In addition to the CGLIB package, scripting languages such as Groovy and BeanShell also use ASM to generate Java bytecode. Direct use of ASM is discouraged, of course, because it requires that you be familiar with the JVM’s internal structure, including the class file format and instruction set.

Native direct memory overflow

The direct memory size can be set using MaxDirectMemorySize (the default is the same as the maximum heap memory size), so an OOM exception will occur. Memory overflow caused by direct memory overflow, a relatively obvious feature is that there is no obvious exception in the HeapDump file. If OOM occurs, and the Dump file is very small, you can consider to focus on the direct memory cause.

Understand constant pools in depth

A Class constant pool

In addition to the class version, field, method, and interface descriptions, the class file contains the Constant Pool Table, which is used to store the various literal and symbolic references generated during compilation.

Symbolic reference

When a Java class (let’s say People) is compiled into a class file, if People references the Tool class, but at compile time People does not know the actual memory address of the referenced class, so symbolic references are used instead.

When the People class is loaded by the class loader, the real memory address of the Tool class can be obtained from the virtual machine. Therefore, the symbol org.simple.Tool can be replaced with the real memory address of the Tool class, and the address can be directly referenced. That is, a symbolic reference is used to replace the reference class at compile time and the virtual machine obtains the actual address of the reference class at load time. A set of symbols describing the referenced object, which can be any literal, as long as it is used unambiguously to locate the object.

Symbolic references are independent of the memory layout implemented by the virtual machine, and the target of the reference is not necessarily already loaded into memory.

literal

  • Text stringString a = "abc"The ABC is the literal
  • Eight basic typesint a = 1This 1 is a literal
  • Declared asfinalThe constant

Run-time constant pool

The Runtime Constant Pool is a run-time representation of the Constant Pool for each class or interface, which contains several different constants:

From numeric literals known at compile time to method or field references that must be parsed at run time. (This is the description in the virtual machine specification, which is very awkward.)

The runtime constant pool is used to dump symbolic reference values from the Class constant pool into the runtime constant pool after the Class is loaded. After the Class is parsed, symbolic references are replaced with direct references.

After JDK1.7, the runtime constant pool was moved to heap memory, which is the physical space and still logically belongs to the method area (which is the logical partition).

In JDK1.8, the method area is implemented using metaclespaces instead of permanent generations, but the method area is not changed. “Your father will always be Your father”. All that changed was the physical location of the content in the method area, but the runtime constant pool and string constant pool were moved to the heap. But no matter how they are physically stored, they logically belong in the method area.

String constant pool

String constant pool is the concept of the most controversial, for a lot of formal documentation, such as virtual machine specifications found without the official definition of the concept, so as not to return to the relationship between runtime constant pool, we from its role and JVM design which is used to solve the problem of what to analyze it, for a moment to understand it as in the area of an area.

In JDK1.8, for example, the String constant pool is stored in the heap and has a lot to do with the java.lang.String class. The reason for designing this area of memory is that the String object, as an important data type in the Java language, occupies the largest amount of memory. Efficient use of strings can improve overall system performance. So to get it right, our focus is really on understanding String.

The String in the Java

A String object is an encapsulated char array and has two member variables: char array and hash value.

Immutability of String objects

The String class is decorated with the final keyword, and the char array is also decorated with final. We know that a class is final to indicate that the class is not inheritable, while char[] is final+private to indicate that the String cannot be changed. Java implements this feature called immutability of Strings, which means that once a String has been created, it cannot be changed.

What are the benefits of Java doing this?

  • Ensure the security of strings. Assuming strings are mutable, strings can be maliciously modified.
  • This ensures that hash attribute values do not change frequently, ensuring uniqueness and enabling key-value caching for containers like HashMaps.
  • String constant pooling can be implemented. In Java, there are usually two ways to create string objects. One is to create them as string constants, such asString str="ayue"; The other is string variables created through the new form, such asString str = new String("ayue").
How to create String and how to allocate memory
  1. String str = "ayue"

    When a string object is created in this way in code, the JVM first checks to see if the object is in the string constant pool, and if so, returns a reference to the object, otherwise a new string will be created in the constant pool. This saves memory by reducing repeated creation of string objects with the same value. (STR is just a reference)

  2. String str = new String("ayue")

    First, when the class file is compiled, the “ayue” constant string will be put into the constant structure. When the class is loaded, “ayue” will be created in the constant pool. Second, when calling new, the JVM command will invoke the String constructor and create a String in heap memory by referring to the “ayue” String in the constant pool. Finally, STR will refer to String.

  3. Entity object assignment

    With new, the object is created in the heap, and with assignment, a string object is created in the constant pool and copied to the heap. The copying process is to push the String from the constant pool onto the stack, and then use the String constructor to take the String from the stack as an argument to the constructor.

    This constructor is an assignment of a char array, not a new one, so it references a string object in the constant pool.

  4. String str = "a" + "yu" + "e"

    Concatenation of strings is common in programming. Strings are immutable, so if we add strings and concatenate the strings we want, wouldn’t that create multiple objects? For “a” + “yu” + “e” :

    First an A object is generated, which is regenerated into an AYU object, and finally an Ayue object, which is three objects. In theory, this code is inefficient. But the compiler automatically optimizes this line of code, and when you compile it, you’ll see that the compiler automatically optimizes this line of code, which is String STR = “ayue”.

  5. String.intern()

    The intern() method of String, which reuses the object if it has the same value in the constant pool, returns an object reference.

    So, what do you think should be printed for this code?

Personal think the JVM memory structure is more partial concept, known as the eight-part essay writing, but behind the involves GC tuning, and so on, are all based on the basic concept, so when they study the JVM is dull, and may see forget tomorrow today, this is very normal, I, too, so if you want to learn, Then put in the effort.

reference

  • Understanding the Java Virtual Machine in Depth _ Zhiming Zhou