A few days ago, I wrote “Java Bytecode” and “How to Read Obscure Class files” two articles, mainly from the bytecode aspect of the composition of classes.

This article looks at the life cycle of in-memory classes in terms of when the JVM loads bytecode files and the class loading process.

Read this article to find out

  1. Know when the JVM loads a class
  2. Master the life cycle of a class

Class loading timing

Java source files are converted by the compiler into Class files, which contain the JVM virtual machine instructions and the logic for running the program.

The classloader reads the file binary stream based on the fully qualified name of the Class file, stores it in the runtime method area, and identifies the data structure of the Class in runtime memory by creating a java.lang.Class object in the heap.

When do you try to read a Class file for Class loading during program execution?

There are several scenarios:

  1. encounternew.getstatic.putstatic.invokestaticFour instructions, corresponding to the programnewInstance object that reads or sets static nonfinalField to call a static method.
  2. usejava.lang.reflectThe package method makes a reflection call to the class, corresponding to the callClass#forNameMethods;
  3. Initialization of a class is triggered when its parent is not initialized.
  4. When the JVM starts, the user specifies a main class to execute (the class containing the main method), which is initialized first.
  5. The use of JDK1.7java.lang.invoke.MethodHandleExample and the parsing result isREF_getStatic.REF_putStatic.REF_invokeStaticMethod handle is initialized when the corresponding class is uninitialized.
  6. When using JDK1.8 to define an interface with default methods, the interface is initialized first if the interface implementation class is initialized.

Static fields read by getStatic and putStatic cannot include fields modified by final because fields modified by final are written to static fields in the constant pool at compile time.

To put it bluntly: if class A uses class B’s static final variable in the code logic, class B will not attempt to load it.

Knowing when the class is loaded, what happens when the class is loaded?

Class life cycle

The diagram above shows me the class loading process, which can be divided into five major stages:

  • Loading load
  • Linking connection
    • The Verification test
    • Preparation for
    • Resolution parsing
  • Initialization initialize
  • Using the use of
  • Unloading uninstall

Loading

By loading Class file binary byte data and mapping it to a program readable Class object structure.

The loading process goes through the following steps:

  1. Get the binary byte stream that defines the class by its fully qualified name. Byte streams can come from anywhere, not just compiled from Java source, such as network transport.
  2. Convert the static storage structure represented by this byte stream to the runtime data structure of the method area;
  3. Generates a representation of this class in memoryjava.lang.ClassObject that serves as the various data access points for this class.

This phase of the work is done by the class loader controlling the byte stream retrieval method, but the array class is created directly by the virtual machine, but its element types still need to be loaded by the class loader.

It is worth noting that Class objects are not necessarily stored in the Java heap memory, but may also be stored in the method area, as in the implementation of the HotSpot VIRTUAL machine.

Linking

The connection stage includes Verification, Preparation, and Resolution. Some of the steps in this phase may exist in the load process.

The following three processes are started in sequential order, but there may be some overlap between them.

Verification

Ensure that the byte stream of the Class file contains information that meets the requirements of the current virtual machine and does not harm the virtual machine.

The verification content is roughly divided into four parts

  1. File format verification. Mainly used to verify whether the byte stream conforms to the Class file format specification, this part can refer to the Class file structure table this article. The verification also includes whether magic OxCAFEBABE starts, whether the primary and secondary version numbers are within the scope of the current VIRTUAL machine, and so on. The bytecode is not entered into the method area storage structure until it has been validated at this stage.

  2. Metadata validation. It is used to verify the semantics of metadata information of a class and ensure that there is no metadata information that does not comply with Java language specifications. For example, whether a class other than java.lang.Object has a parent class; If not, whether the abstract class implements its parent class or an interface that requires subclasses to override all methods implemented.

  3. Bytecode verification. Mainly through data flow and control flow analysis, to determine whether the semantics of the program is legitimate and reasonable, for the method body of the class verification analysis, to ensure that the method will not make harm to virtual machine security events during running. Such as ensuring that jump Pointers do not jump to bytecode instructions outside the method; Ensure that the data type and sequence of instruction code operating on the stack work together at any time, without the occurrence of an int at the top of the stack being loaded into the local variable table as long.

  4. Symbol reference validation. Validation occurs when the virtual machine converts symbolic references to direct references (the parsing phase). The verification is not limited to whether a class can be found for a fully qualified name described by a string in a symbolic reference; Whether a field descriptor for a method exists in the specified class, as well as methods and fields described by simple names. Ensure that the parsing behavior performs properly during the parsing phase.

Preparation

Allocates memory for class variables and sets their initial values.

For example, declare the following static variables

public static int A = 1; Public static final int B = 2;Copy the code

Class A is initialized to 0 after allocating memory for it in the preparation phase, and the actual assignment of 1 is done in the class constructor < clinit >(). This is not the case with B, where javac generates a ConstantValue attribute for class B at compile time, which is assigned to 2 (field property table).

Resolution (Resolution)

Replaces symbolic references in the constant pool with direct references.

Symbolic references are a set of literals used to describe the referenced target, the form of which is explicitly defined in the Class file format. A direct reference can be a pointer to a target, a relative offset, or a handle that can be indirectly located to the target.

The former is independent of the memory layout implemented by the virtual machine, while the latter is. If there is a direct reference, the target must be in memory.

Whenever the following 16 bytecode instructions are used to manipulate symbol references, the referenced symbol references are parsed before the instruction is executed:

Anewarray, checkcast, getField, getstatic, instanceof, Invokedynamic, InvokeInterface, Invokespecial, Invokestatic, Invokevirtual, LDC, LDC_W, Multianewarray, new, putField, putStatic

Therefore, the virtual machine can determine whether to parse symbolic references from the constant pool as soon as the class is loaded by the loader or wait until a symbolic reference is about to be used.

The parse action is mainly for class or interface, field, class method, interface method, method type, method handle, and call point qualifier 7 classes, respectively corresponding to:

CONSTANT_Class_info, CONSTANT_Fieldref_info, CONSTANT_Methodref_info, CONSTANT_InterfaceMethodref_info, CONSTANT_MethodType_info, CONSTANT_MethodHandle_info, CONSTANT_InvokeDynamic_info,

Interested friends can refer to the in-depth understanding of the Java Virtual Machine: JVM Advanced Specific and Best Practices book or the official documentation involved in parsing content, too large to elaborate here.

Initialization (Initialization)

Executes Java code defined in a class, initializing class variables and other resources according to a program defined plan.

The compiler automatically collects all of the class variable assignment behavior and static statement blocks in the class and combines them to produce the Clinit method, whose statements are executed in the same order as they appear in the source file.

The virtual machine ensures that this code is executed correctly and once in a single/multithreaded environment, with the parent clinit method called before the subclass’s Clinit method is called.

It’s worth noting that the interface also generates Clinit methods, but not the same as classes. Interface execution of the Clinit method does not require the parent interface’s Clinit method to be executed first. The parent interface initializes the Clinit method only when a variable defined in the parent interface is used.

The Clinit method is a thread-safe operation that ensures proper locking and synchronization in multithreaded environments. If multiple threads initialize a class at the same time, only one thread will execute and the other threads will have to block and wait.

Using

The usage phase of a Class, the period between the existence of the Class object and its uninstallation.

At this stage the program may generate a large number of instance objects of the class and perform object behavior. Even if there is no instance object of any class in memory, it may not be unloaded.

2. Class Unloading

Once a Class is loaded, the Class and Meta information is stored in the PermGen Space area, which is typically stored permanently for the duration of the program.

If you want to uninstall a class, the following three conditions must be met.

  1. All instances of this class have been collected by GC;
  2. Loading of the classClassLoaderThe instance has been collected by GC;
  3. Of the classjava.lang.ClassObject is not referenced.

Meta, or metadata, is data that describes the methods, fields, classes, packages, and other elements of an application. The common Anotation is metadata.

The JVM specification states that Bootstrap Classloader cannot be unloaded during runtime, and the types loaded by the Extension Classloader are almost unlikely to be unloaded during runtime.

This is because the program can directly or indirectly scope classes that start with standard extension classes such as javax.xx. If the developer custom class loader is used to load these classes, it is not possible to try to unload them with the help of virtual machine garbage collection unless the context of these classes is very simple.

Although the unloading conditions are harsh, it is still possible. Since the timing of GC is unpredictable, unloading classes is also unpredictable.

Welcome to the Android Zen account to share valuable and thoughtful technical articles with you. Can add wechat “Ming_Lyan” remarks “into the group” to join the technical exchange group, discussion of technical problems is strictly prohibited all advertising irrigation. If you have technical problems in the Android field or have doubts about your future career plan, discuss with us. Welcome to the party.