Summary of Java virtual machine interview questions

title address
Summary of Java Virtual Machine Interview Questions (2022 Edition) https://blog.csdn.net/qq_37924396/article/details/125881033
Summary of Java Collection Interview Questions (2022 Edition) https://blog.csdn.net/qq_37924396/article/details/126058839
Summary of Mysql database interview questions (2022 version) https://blog.csdn.net/qq_37924396/article/details/125901358
Summary of Spring Interview Questions (2022 Edition) https://blog.csdn.net/qq_37924396/article/details/126354473
Summary of Redis interview questions (2022 version) https://blog.csdn.net/qq_37924396/article/details/126111149
Summary of Java Concurrency Interview Questions (2022 Edition) https://blog.csdn.net/qq_37924396/article/details/125984564
Summary of Distributed Interview Questions (2022 Edition) https://blog.csdn.net/qq_37924396/article/details/126256455

1. JVM memory model

insert image description here

1.1 heap

1. The java heap is the largest piece of memory managed by the java virtual machine. It is a memory area shared by all threads and is created when the virtual machine starts. The sole purpose of this memory area is to store object instances.
2. The description in the Java Virtual Machine Specification is: All object instances and arrays must be allocated on the heap.
3. The java heap is the main area managed by the garbage collector, so it is also called the "GC heap".
4. From the perspective of memory recovery, the java heap can be divided into: the new generation and the old generation.
5. From the perspective of memory allocation, multiple thread-private allocation buffers may be divided in the Java heap shared by threads.
6. No matter how it is divided, it has nothing to do with the storage content. No matter which area, it stores object instances. Further division is to reclaim memory better or allocate memory faster.
7. According to the Java virtual machine specification, the java heap can be in a physically discontinuous memory space. The current mainstream virtual machines are all extensible (controlled by -Xmx and -Xms). If there is no memory in the heap to complete the instance allocation, and the heap can no longer be expanded, an OutOfMemoryError exception will be thrown.

1.2 Method area

1. The method area is a memory area shared by all threads. It is used to store data such as class information, constants, static variables, and code compiled by the real-time compiler that have been loaded by the Java virtual machine .
2. It has a special name called Non-Heap (non-heap). When the method area cannot meet the memory allocation requirements, an OutOfMemoryError exception is thrown.

1.3 Program Counter

1. The program counter is a small memory space, which can be seen as: saving the address (line number) of the bytecode instruction being executed by the current thread
2. Since the multithreading of the Java virtual machine is switched by threads in turn and It is implemented by allocating processor execution time , and a processor will only execute instructions in one thread. Therefore, in order to restore to the correct execution position after thread switching, each thread has an independent program counter, and the counters between each thread do not affect each other and are stored independently. Called "thread-private" memory. The program counter memory area is the only area in the virtual machine that does not specify the OutOfMemoryError condition.

1.4 Virtual machine stack

1. The java virtual machine is private to the thread, and its life cycle is the same as that of the thread.
2. The virtual machine stack describes the memory model of Java method execution: each method will create a stack frame (Stack Frame) to store local variable table, operand stack, dynamic link, method exit and other information while executing .

Explanation: There are units in each virtual machine stack, the unit is the stack frame, and one method has one stack frame. In a stack frame, he also needs to store, local variables, operand stack, dynamic link, export, etc.
insert image description here
Parsing the stack frame:
1. Local variable table: It is used to store our temporary 8 basic data types, object reference address, and returnAddress type. (The returnAddress stores the instruction address of the bytecode to be executed after return.)
2. Operand stack: The operand stack is used for operations. For example, there is i = 6*6 in the code, which is at the beginning It will be operated at any time, read our code, perform calculations and then put it into the local variable table
3. Dynamic link: If there is a service.add() method in my method, it needs to be linked to other methods , which is where dynamic linking, where the link is stored.
4. Export: What is the export? If the export is normal, it will return; if it is not normal, it will throw an exception.

1.5 Native method stack

1. The native method stack is easy to understand. It is very similar to the stack, except that the stack word with the native keyword is added to the method.
2. It is a service for the virtual machine stack to execute Java methods (that is, bytecodes) for the virtual machine.
3 The method of the .native keyword is invisible, you must go to the official website of Oracle to download it, and most of the source code modified by the native keyword is C and C++ code.
4. In the same way, the local method stack is the code of C and C++

2. JVM garbage collection mechanism

2.1 How to judge whether the object is alive

  • Reference counting algorithm
    1. The reference counting method is that if an object is not pointed to by any reference, it can be regarded as garbage. The disadvantage of this method is that it cannot detect the existence of rings.
    2. First of all, it needs to be declared that at least mainstream Java virtual machines do not use reference counting algorithms to manage memory.
    3. What is the reference counting method: when each object is created, a counter is bound to the object. Whenever a reference to the object is added, the counter is incremented; whenever a reference to it is deleted, the counter is decremented. In this way, when there is no reference pointing to the object, the counter is 0, which means that the object is dead

  • The reachability analysis
    uses a series of objects called GC Roots as the starting point, and searches downward from these points. The path traveled by the search is called a reference chain. When an object does not have any reference chain connected to GC Roots, it is considered Object is unreachable.

Even objects that are unreachable in the reachability analysis are not necessarily dead, but are in the probation stage. To really die, at least two markings are required, which is related to finalize.

2.2 Garbage collection algorithm

Common algorithms include the copy algorithm of the new generation, and the mark clearing and mark finishing algorithms of the old generation.

1. Replication Algorithm

In order to solve the problem of efficiency, a "copy" collection algorithm appeared, which divides the memory capacity into two pieces of equal size, and only uses one of them at a time. When the memory of this piece is used up, the surviving objects are copied to another piece above, and then clean up the used memory space. In this way, half of the area is reclaimed every time, and there is no need to consider the problem of memory fragmentation when allocating memory. You only need to move the top pointer of the heap and allocate memory in order. The implementation is simple and the operation is efficient. The cost is that the memory is reduced. half of the original.
insert image description here

2. Mark-clear algorithm

The most basic collection algorithm is divided into two stages of "marking" and "clearing". First, mark the objects that need to be recycled, and then uniformly recycle all marked objects after marking. All of them are called marking algorithms. Follow-up The collection algorithms are all based on this idea and should be good for them.

The shortcomings of this algorithm have two aspects:
1. Efficiency problem, the efficiency of marking and clearing is not high.
2. Space problem, after marking and clearing, a large number of discontinuous memory fragments will be generated. When a large object needs to be allocated during the running of the program , unable to find enough contiguous memory and had to trigger a garbage collection action in advance
insert image description here

3. Marking-Collating Algorithm

The copy collection algorithm will perform more copy operations when the object survival rate is relatively high, and the efficiency will become lower. More importantly, if you don't want to waste 50% of the space, you need to use additional space for allocation guarantees to deal with the extreme situation where all objects in the used memory are 100% alive. For the "mark-sort" algorithm, the mark process is the same as "mark-clear
" "Algorithm is the same, but the next step is not to clean up recyclable objects directly, but to move all surviving objects to one end, and then clear the memory outside the boundary
insert image description here

4. Generational collection algorithm

The generational collection algorithm is currently the algorithm used by most JVM garbage collectors. Its core idea is to divide memory into several different areas according to the life cycle of objects. Generally, the heap area is divided into the old generation (Tenured Generation) and the new generation (Young Generation). The characteristic of the old generation is that only a small number of objects need to be recycled each time garbage collection is performed, while the characteristic of the new generation is that each garbage collection There are a large number of objects that need to be recycled, so the most suitable collection algorithm can be adopted according to the characteristics of different generations.

At present, most garbage collectors use the copy algorithm for the new generation, because most of the objects are recovered for each garbage collection in the new generation, which means that the number of operations that need to be copied is less, but in practice it is not 1:1 Generally speaking, the new generation is divided into a larger Eden space and two smaller Survivor spaces. Each time the Eden space and one of the Survivor spaces are used, when recycling, Copy the surviving objects in Eden and Survivor to another Survivor space, and then clean up Eden and the Survivor space just used.

And because the characteristic of the old generation is that only a small number of objects are recycled each time, the mark-sorting algorithm (compression method) is generally used.

2.3 Common Garbage Collectors

insert image description here

The figure shows 7 kinds of collectors that act on different generations, namely the new generation collectors Serial, ParNew, Parallel Scavenge, the old generation collectors CMS, Serial Old, Parallel Old and the whole heap collector G1. If there is a wire between two collectors, they can be used together. The region the virtual machine is in indicates whether it belongs to the young generation or the old generation collector.

The Serial collector
is single-threaded, simple and efficient. For an environment limited to a single CPU, the Serial collector has no thread interaction overhead, so concentrating on garbage collection can naturally obtain the highest single-thread recycling efficiency. When the collector performs garbage collection, it must suspend all other worker threads until it ends (Stop The World).

ParNew collector
The ParNew collector is actually a multi-threaded version of the Serial collector. Except for the use of multithreading, the rest of the behavior is exactly the same as the Serial collector (parameter control, collection algorithm, Stop The World, object allocation rules, recycling strategies, etc.), and there are also STW problems.

You can use the -XX:ParallelGCThreads parameter to set the number of threads for garbage collection. The new generation collector is preferred in many virtual machines running in Server mode, because it is the only one other than Serial that works with the CMS collector.

Parallel Scavenge collector
This is a multi-threaded collector that can control throughput, so it is also called a throughput-first collector. Compared with the ParNew collector, Parallel Scavenge can use XX:MaxGCPauseMillis to control the maximum garbage collection pause time and XX:GCRatio to directly set the throughput.

At the same time, it supports GC adaptive adjustment strategy. That is, the Parallel Scavenge collector can set the -XX:+UseAdptiveSizePolicy parameter. When it is turned on, there is no need to manually specify the size of the new generation (-Xmn), the ratio of Eden to Survivor area (-XX:SurvivorRation), the age of the object promoted to the old age (-XX:PretenureSizeThreshold), and other information, the virtual machine runs according to the system Status collects performance monitoring information and dynamically sets these parameters to provide optimal pause times and highest throughput.

Serial Old Collector
The old version of the Serial Collector is also a single-threaded collector and uses a mark-sort algorithm.

The Parallel Old collector
is an old generation version of the Parallel Scavenge collector, which uses a mark-sort algorithm. It is suitable for occasions that focus on high throughput and are sensitive to CPU resources.

CMS collector
A collector whose goal is to obtain the shortest collection pause times. It is also a concurrent collector based on the mark-sweep algorithm. Concurrency and synchronization here are several multi-threaded parallel collectors mentioned above, which means that user threads and garbage collection threads work at the same time (not necessarily in parallel, but may be executed alternately).

It is very suitable for scenarios such as paying attention to the response speed of the service, hoping to minimize the system pause time, and bringing a better experience to users.

G1 collector
is a garbage collector for server-side applications.

4. Class loading mechanism

4.1 What is class loading

The virtual machine loads the data describing the class from the Class file to the memory, and verifies, converts, parses, and initializes the data, and finally forms a Java type that can be directly used by the virtual machine. This is the class loading mechanism of the virtual machine.

4.2 The process of class loading

In Java, a class can be divided into loading, verification, preparation, analysis, initialization, use and unloading steps from definition to use. Among them, verification, preparation and parsing can be collectively referred to as connection.
insert image description here

  • Loading
    1) Obtain the binary byte stream that defines this class through the fully qualified class name;
    2) Convert the static storage structure represented by this byte stream into a runtime data structure in the method area;
    3) Generate a representation in memory The java.lang.Class object of this class is used as the access entry of various data of this class in the method area.

  • Verification
    Verification is the first step in the connection phase. The purpose of this phase is to ensure that the information contained in the byte stream of the Class file meets the requirements of the current virtual machine and will not endanger the safety of the virtual machine itself.
    1) File format verification: This stage ensures that the input byte stream can be correctly parsed and stored in the method area, and the format meets the requirements for describing a Java type information. For example, whether it starts with the magic number 0xCAFEBABE, whether the major and minor version numbers are within the processing range of the current virtual machine, constant rationality verification, etc.
    2) Metadata verification: This stage ensures that there is no metadata information that does not conform to the Java language specification. For example, whether there is a parent class, whether the inheritance chain of the parent class is correct, whether the abstract class implements all the methods required to be implemented in its parent class or interface, whether the fields and methods conflict with the parent class, etc.
    3) Bytecode verification: Through data flow and control flow analysis, it is determined that the program semantics are legal and logical. For example, to ensure that jump instructions do not jump to bytecode instructions outside the method body.
    4) Symbolic reference verification: Occurs in the parsing phase to ensure that symbolic references can be converted into direct references.

    You can consider using the -Xverify:none parameter to turn off most of the class verification measures to shorten the virtual machine class loading time.

  • Preparations
    Allocate memory for class variables and set the initial value of class variables. The memory used by these variables will be allocated in the method area.

  • Resolution
    The virtual machine replaces symbolic references in the constant pool with direct references. The parsing action is mainly performed on 7 kinds of symbol references of class or interface, field, class method, interface method, method type, method handle and call site qualifier.
    Also to support runtime binding, the resolution process can start after initialization in some cases.

  • Initialization
    At the initialization stage, the Java program code defined in the class is actually executed. This stage is the process of executing the () method. This method is generated by the compiler automatically collecting the assignment actions of all class variables in the class and merging the statements in the static code block in sequence according to the order in which the statements appear in the source file.

This procedure does not include statements in constructors. The constructor is to initialize the object. After the class loading is completed, the () method will be called when the object is created to initialize the object.

4.3 Class loading order

1) Parent class static variable/static initialization block - subclass static variable/static initialization block;
2) Parent class variable/initialization block - parent class constructor;
3) Subclass variable/initialization block - subclass constructor.

4.4 Class loading timing

For loading, there is no mandatory constraint in the Java virtual machine specification, which can be freely grasped by the specific implementation of the virtual machine. But for the initialization phase, the virtual machine specification strictly stipulates that the class must be initialized immediately in the following situations. If the class has not been initialized, its initialization needs to be triggered first.

1) When encountering new (using new instance object), getStatic (reading a static field), putstatic (setting a static field), invokeStatic (calling a static method of a class), these four instruction bytecode commands;

2) When using the methods of the Java.lang.reflect reflection package to make reflective calls to the class, if the class has not been inited at this time, it will be inited first;

3) When initializing a class, if its parent class is not initialized, first initialize the parent class;

4) When the JVM starts, the user needs to specify a main class to be executed (the class containing main), and the virtual machine will execute this class first;

5) When using the dynamic language support of JDK 1.7, when java.lang.invoke.MethodHandler is instantiated, the result is the handle of REF-getStatic/REF_putstatic/REF_invokeStatic, and if the classes corresponding to these handles are not initialized, they should be initialized first.

The behavior in the above five scenarios is called an active reference to a class. In addition, all ways of referencing classes will not trigger initialization, called passive references, such as:

1) Referencing the static fields of the parent class through the subclass will not cause the subclass to be initialized.

2) Referencing a class through an array definition does not trigger initialization of this class. MyClass[] cs = new MyClass[10];

3) The constants will be stored in the constant pool of the calling class during the compilation phase, and essentially there is no direct reference to the class defining the constant, so the initialization of the class defining the constant will not be triggered.

4.5 What is a class loader

The class loader is responsible for loading all classes. An application program consists of N multiple classes. When a java program starts, it does not load all the classes at one time and then runs them. It always first loads the basic classes that guarantee the program to run Loaded into the Jvm, other classes are loaded when the jvm is used, which saves memory overhead, and generates a java.lang.Class instance object for all classes loaded into the memory. Once a class is loaded into the JVM, the same class will not be loaded again. Just as an object has a unique identifier, a class loaded into the JVM also has a unique identifier. In Java, a class is identified by its fully qualified class name (including package name and class name); but in JVM, a class is uniquely identified by its fully qualified class name and its class loader. For example, if there is a class named Person in the pg package, which is loaded by the class loader ClassLoader instance kl, then the Class object corresponding to the Person class is expressed as (Person.pg.kl) in the JVM. This means that the classes with the same name loaded by the two class loaders: (Person.pg.kl) and (Person.pg.kl2) are different, and the classes they load are completely different and incompatible with each other.

4.6 What class loaders are there

  • Bootstrap ClassLoader: (Start Class Loader) : Implemented by C++, it is part of the virtual machine itself. Responsible for loading the class library stored in the lib directory and recognized by the virtual machine into the memory of the virtual machine. It is used to load the core class of Java, which is implemented with native code and does not inherit from java.lang.ClassLoader (responsible for loading All classes in jre/lib/rt.jar in $JAVA_HOME are implemented by C++, not ClassLoader subclasses). Since the boot class loader involves the local implementation details of the virtual machine, developers cannot directly obtain the reference of the boot class loader, so direct operations through references are not allowed.

  • Extension ClassLoader (extension class loader) : It is responsible for loading the JRE extension directory, lib/ext or the class of the JAR package in the directory specified by the java.ext.dirs system property. Implemented by the Java language, the parent class loader is null.

  • Application ClassLoader (application class loader/system class loader) : It is responsible for loading the -classpath option from the Java command, the java.class.path system property, or the JAR package and class specified by the CLASSPATH variable when the JVM starts path. The program can obtain the system class loader through the static method getSystemClassLoader() of ClassLoader. If not specified, user-defined class loaders use this class loader as the parent loader. Implemented by the Java language, the parent class loader is ExtClassLoader.

When a program actively uses a class, if the class has not been loaded into memory, the JVM will initialize the class through three steps: loading, connecting, and initializing. If there is no accident, the JVM will complete 3 steps in a row, so sometimes these 3 steps are collectively referred to as class loading or class initialization.

4.7 Class loading mechanism

The class loading mechanism of JVM mainly has the following three types.
1. Overall responsibility : The so-called overall responsibility means that when a class loader is responsible for loading a class, other classes that the class depends on and references will also be loaded by the class loader, unless another class loader is used to load enter.
2. Parent delegation : The so-called parent delegation is to let the parent class loader try to load the Class first, and only try to load the class from its own class path when the parent class loader cannot load the class. In layman's terms, when a specific class loader receives a request to load a class, it first entrusts the loading task to the parent loader, and then recurses in turn. If the parent loader can complete the class loading task, it returns successfully; only the parent When the loader cannot complete the loading task, it will load it by itself.
3. Cache mechanism : The cache mechanism will ensure that all loaded Classes will be cached. When a certain Class needs to be used in the program, the class loader will first search for the Class from the cache area. Only when the Class does not exist in the cache area object, the system will read the binary data corresponding to the class, convert it into a Class object, and store it in the buffer. This is why after modifying the Class, the JVM must be restarted for the changes made by the program to take effect.

4.8 Parental delegation model

insert image description here
The working principle of the parent delegation mechanism
If a class loader receives a class loading request, it will not load it first, but delegate the request to the parent class loader for execution. If the parent class loader still has its parent class Loader, further delegate upwards, and recurse in turn. The request will eventually reach the top-level startup class loader. If the parent class loader can complete the class loading task, it will return successfully. If the parent class loader cannot complete the loading task, the child loader This is the parental delegation model, that is, each son is very lazy, and every time he has a job, he will leave it to his father to do it. When the father says that I can’t do it, the son will find a way by himself. to finish.

Advantages of the parental delegation mechanism: The
advantage of adopting the parental delegation mode is that the Java class has a hierarchical relationship with priority along with its class loader. Through this hierarchical level, repeated loading of classes can be avoided. When the parent When the class has already been loaded, there is no need for the child ClassLoader to load it again. Secondly, considering security factors, the types defined in the java core api will not be replaced at will. Suppose a class named java. The class with this name is found in the core Java API, and it is found that the class has been loaded. It will not reload the java.lang.Integer passed over the network, but directly return the loaded Integer.class, which can prevent the core API from Libraries are tampered with at will.

4.9 How to break the parental delegation model?

The principle of the parental delegation mechanism is in the loadClass() method, you only need to bypass this method.

  • To use a custom class loader, override the loadClass() method. (Note that it is not the findClass() method)
  • Set the associated class loader (thread context class loader) for the current thread, and use the SPI (Service Provider Interface) mechanism to bypass the loadclass() method.
    The second method has been widely used, such as JDBC, Dubbo, etc.

4.10 Class loading method

1. Create an instance of a class with the new keyword (static loading)
and load it with the new method at runtime,
such as: Dog dog = new Dog();

2. Call the Class.forName() method (dynamic loading)
to load the type through reflection and create an object instance
such as: Class clazz = Class.forName("Dog");
Object dog = clazz.newInstance();

3. Call the loadClass() method of a certain ClassLoader instance (dynamic loading)
to load through the loadClass() method of the ClassLoader instance. An application can implement its own class loader by inheriting from ClassLoader.
Such as: Class clazz = classLoader.loadClass("Dog");
Object dog = clazz.newInstance()

5. Tuning

5.1 Tuning tools?

1.jdk comes with tools

First of all, JDK comes with many monitoring tools, which are located in the bin directory of JDK, among which the two most commonly used monitoring tools are jconsole and jvisualvm.
1) jps: Similar to ps on Linux, it is used to view the processes of virtual machines that have access and display their process numbers. When no hostid is specified, the default is to look at the native JVM process.

2) jinfo: It can output and modify some parameters of the running Java process.

3) jstat: It can be used to monitor the size and memory usage of various heaps and non-heaps in the JVM memory.

4) jstack: a stack trace tool, generally used to view the situation that a process contains threads.

5) jmap: Print out all the objects in the memory of a JVM process, generally used to check the memory usage.

6) jconsole: a GUI monitoring tool that can display various data in a graphical form and supports remote connections.

5.2 Common tuning parameters?

1. Common settings

1) -Xms: Initial heap size, when the JVM starts, the size of the heap space is given.

2) -Xmx: The maximum heap size, during the running of the JVM, if the initial heap space is insufficient, how much can it expand to the maximum.

3) -Xmn: Set the size of the young generation in the heap. The entire heap size = young generation size + old generation size + permanent generation size.

4) -XX:NewSize=n: Set the initialization size of the young generation.

5) -XX:MaxNewSize=n: Set the maximum value of the young generation.

6) -XX:NewRatio=n: Set the ratio of the young generation to the old generation. For example, when n = 3, it means that the ratio of the young generation to the old generation is 1:3, and the young generation accounts for 1/4 of the entire young generation + old generation.

7) -XX:SurvivorRatio=n The ratio of the Eden area to the two Survivor areas in the young generation. Note that there are two Survivor areas. 8 means two Survivors: eden=2:8, that is, one Survivor accounts for 1/10 of the young generation, and the default is 8.

8) -Xss: Set the stack size of each thread. After JDK5, the Java stack size of each thread is 1M, and the stack size of each thread was 256K before.

9) -XX:ThreadStackSize=n: thread stack size.

10) -XX:PermSize=n: Set the initial value of the persistent generation.

11) -XX:MaxPermSize=n: Set the size of the permanent generation.

12) -XX:MaxTenuringThreshold=n Set the maximum age of young garbage objects. If it is set to 0, the young generation objects will directly enter the old generation without going through the Survivor area.

2. Uncommon settings

1) -XX:LargePageSizeInBytes=n: Set the memory page size of the heap memory.

2) -XX:+UseFastAccessorMethods: Optimize the performance of getter methods of primitive types.

3) -XX:+DisableExplicitGC: It is forbidden to explicitly call System.gc() at runtime, which is enabled by default.

4) -XX:+AggressiveOpts: Whether to enable the latest tuning results of the JVM development team. Such as compilation optimization, biased locks, parallel old generation collection, etc., are started by default after JDK 6.

5) -XX:+UseBiasedLocking: Whether to enable biased locking, JDK 6 is enabled by default.

6) -Xnoclassgc: Whether to disable garbage collection.

7) -XX:+UseThreadPriorities: Use the priority of the local thread, enabled by default.

3. Recycler related settings

1) -XX:+UseSerialGC: Set the serial collector, the young belt collector.

2) -XX:+UseParNewGC: Set the young generation to collect in parallel. Can be used concurrently with CMS collection. The JVM above JDK 5 will set itself according to the system configuration, so there is no need to set this value.

3) -XX:+UseParallelGC: Set the parallel collector, the goal is to achieve a controllable throughput.

4) -XX:+UseParallelOldGC: Set the parallel old generation collector, JDK 6 supports parallel collection of the old generation.

5) -XX:+UseConcMarkSweepGC: Set the old generation concurrent collector.

6) -XX:+UseG1GC: Set the G1 collector, JDK 9 default garbage collector

Guess you like

Origin blog.csdn.net/qq_37924396/article/details/125881033