JVM mechanism (overall context)

How does Java code work

Suppose we develop a Java Web system and deploy it to run in Tomcat.

  1. The first is to use IDEA to write demoService.java source files (many)
  2. Multiple.java source files are then packaged into WAR or JAR packages and deployed in a Web container such as Tomcat
  3. Start Tomcat. After Tomcat is successfully started, the Web system can provide external services
    1. Connector : Http(Technology)
    2. Container: Servlet(Business)

We can also start the Web program with the Java -jar xx.jar command

graphic

Homework problems

Since a “Java” file can be compiled to a “.class “file and run, it must be possible to decompile a “.class” file to a “Java” file.

But in this case, if your company’s system code is compiled in.class format, but someone else gets it, it can be decompiled back to steal the source code of your company’s core system. How do you think we should solve this problem?

How do you handle the “.class” file so that it doesn’t get retrieved and decompiled to get the company’s source code?

  1. First, when you compile, you can use some small tools to encrypt the bytecode, or do obfuscate and so on

    There are many third-party companies that specialize in commercial grade bytecode file encryption, so you can pay for their products.

  2. Then consider using custom class loaders to decrypt files for encrypted classes during class loading. This will ensure that your source code is not stolen.

JVM class loading mechanism

When does the JVM load a class

When you use the class in your code, go back and load the class. (Time loading)

The loading process

Load -> Verify -> Prepare -> Parse -> Initialize -> Use -> Uninstall

1. Verify, prepare, and parse

1.1 validation

Verify that the contents of your.class file conform to the specified specification against the Java virtual machine specification.

If your “.class “file has been tampered with and the bytecode in it is not conforming to the specification at all, then the JVM cannot execute the bytecode!

1.2 to prepare
  1. Allocate memory space to a class.

  2. It then allocates memory for the class’s static variables and sets a default initial value

    public static int flushInterval;

    • toflushIntervalVariables allocate a certain amount of memory space
    • Set the default value to 0
1.3 analytical

Replace a symbolic reference with a direct reference

2. Initialization (core phase)

public static int flushInterval = Configuration.getInt("replica.flush.interval");
Copy the code

We know that configuration.getint () assignment to the flushInterval class variable is not performed in the prepare phase.

Configuration.getInt(Replica.flush. Interval) assignment is complete during initialization. Procedure

The static block is also executed.

 public static Map<String, Replica> replicas;

    static {
        loadReplicaFromDish();
    }

    private static void loadReplicaFromDish(a) {
        replicas = new HashMap<>();
    }
Copy the code
Initialization rule

When is a class initialized?

Generally speaking, there are the following times:

  • Such as”new ReplicaManager()“To instantiate an object of the class, this triggers the loading of the class through initialization, prepares the class, and then instantiates an object; (Object instantiation)
  • Or include”main()The main class of the “method” must be initialized immediately.
  • In addition, an important rule is that if you initialize a class whose parent class is not initialized, you must initialize its parent class first

graphic

Class loaders and parent delegation mechanisms

Class loader

As the name suggests, class loaders are used to load classes.

Java comes with the following class loaders:

BootStrap ClassLoader

Is responsible for loading the core classes in the Java directory.

Once your JVM is started, it will first load the core libraries in the “lib” directory of your Java installation directory, relying on the startup class loader.

Extension ClassLoader

Extension ClassLoader is a similar ClassLoader. In your Java installation directory, there is a “lib\ext “directory that contains classes that need to be loaded using the Extension ClassLoader to support your system.

Once the JVM is started, it must also load the ‘lib\ext’ classes from the Java installation directory.

Application ClassLoader

Is responsible for loading classes in the path specified by the “ClassPath” environment variable.

Loosely understood as loading Java code you’ve written, the classloader is responsible for loading the classes you’ve written into memory.

Custom class loaders

Developers who customize class loaders to load classes according to their needs may break the parent delegation mechanism.

Parent delegation mechanism

When an application classloader needs to load a class, it first delegates its own parent classloader to do so, and finally transmits the load to the top-level classloader.

If the parent class loader does not find the class in its own loading scope, it will push down the loading rights to its own child loaders.

Popular shows

For example, if your JVM now needs to load ReplicaManager class, the application classloader will ask its dad, the extension classloader, can you load the class?

Then the extension classloader directly asks his dad, start the classloader, can you load this class? I’m starting the class loader and I’m thinking, I can’t find this class in the Java installation directory, go find it!

Then, we push down the load right to the extension class loader son, the extension class loader looked for a long time, but did not find their own responsible for the directory has the class. At this time he was very angry and said: it is clearly your application loader is responsible for their own, you find yourself.

Then the application class loader is responsible for its own scope, such as that you wrote the system packaged into a JAR package, suddenly found that here! Then I load the class into memory by myself.

This is known as the parent delegate model: get the father to load it, and if not, the son to load it. In this way, you can avoid multiple layers of loader structures that repeatedly load certain classes.

graphic

Class loader hierarchy

The class loading mechanism of Tomcat

Web systems developed in Java, unless they are based on Java writing middleware, are generally deployed using a Web container such as Tomcat.

So if you think about it, Tomcat itself is written in Java, it’s a JVM itself.

The system programs we write are basically a bunch of compiled.class files put into a war package and run in Tomcat.

How can Tomcat’s class loading mechanism be designed to load classes from war packages that we dynamically deploy into the JVM that Tomcat runs, and then execute the code that we write?

  1. Tomcat has custom Common, Catalina, and Shared class loaders that are used to load some of Tomcat’s core base libraries.
  2. Tomcat then has a corresponding WebApp class loader for each Web application deployed in it, which is responsible for loading the classes of the Web application we deploy
  3. As for Jsp classloaders, there is one Jsp classloader for each Jsp.

Tomcat breaks the parent delegation mechanism.

  1. Each WebApp is responsible for loading its own Web application class file, that is, we write a system packaged war package class files (WEB-INF/classes directory class files), do not pass to the upper class loader to load.
Tomcat breaks the parent delegation mechanism

The Tomcat class loader hierarchy

JVM memory partition

Program counter (thread private)

The JVM executes the bytecode instructions (based on the bytecode execution engine) after the.java source files (unreadable by the computer) are compiled into.class bytecode files.

Bytecode file -> bytecode -> bytecode instruction

Bytecode instructions: a sequence of machine instructions that the computer does not know what to do until it has read them.

The program counter is used to record the current execution of the byte code instruction location, that is, to record which byte code instruction execution line.

Each thread has its own program counter that records which byte code instructions are executed by the current thread. (Thread private)

Java virtual Machine stack (thread private)

When Java code is executed, it is executed by a thread.

The Java virtual machine stack is primarily used to hold data such as local variable tables within each method.

  1. Each thread has its own Java virtual machine stack

  2. When a thread executes a method, it creates a stack frame for that method and pushes it into the thread’s Java virtual machine stack

    The stack frame contains the method’s local variable table, operand stack, dynamic links, method exits, and so on

Local method stack

public native int hashCode()

The heap

Save the object

Methods area

This is used to hold classes loaded from the “.class” file. It also contains the constant pool area.

After Java 1.8, this area was changed to MetaSpace(metadata space), called the meta-space, but it still holds various class-related information.

Constant pool

Out-of-heap memory (not managed by the JVM)

With APl like allocateDirect in NIO, memory space can be allocated outside the Java heap.

The out-of-heap memory space is then referenced and manipulated through the DirectByteBuffer in the Java virtual Machine.

public static ByteBuffer allocateDirect(int capacity) {
    return new DirectByteBuffer(capacity);
}
Copy the code

ByteBuffer

What happens to the JVM when this code executes

public class Kafka{
    
  public static void main(String[] args){
  		ReplicaManager replicaManager = newReplicaManager(); replicaManager.loadReplicasFromDish(); }}public class ReplicaManager{
    
    private long replicaCount;
    
    public void loadReplicasFromDish(a){
        Boolean hasFinished = false;
        
        if(isLocalDataCorrupt()){
            // ...}}public Boolean isLocalDataCorrupt(a){
        Boolean isCorrupt = false;
        returnisCorrupt; }}Copy the code
  1. The Kafka class is loaded first

  2. There is a main thread that is ready to execute the Kafka. Main method. The main thread is associated with a program counter that logs which bytecode instructions are executed

  3. The main thread is first associated with a Java virtual machine stack and pushes the main() method’s stack frame into the virtual machine stack

    ReplicaManager replicaManager = new ReplicaManager();

  4. The JVM intends to create a ReplicaManager object, but finds that the ReplicaManager Class has not been loaded, so it loads the ReplicaManager Class

  5. Create a ReplicaManager object in the heap and add it to the local variable table of the main method stack frame to reference the address of the ReplicaManager object in the Java heap memory

    replicaManager.loadReplicasFromDish()

  6. Create the stack frame corresponding to the loadReplicasFromDish method, push it into the Java virtual machine stack associated with the main thread, and so on

  7. When the method corresponding to the stack frame at the top of the Java virtual machine stack finishes executing, the stack frame is sent out of the stack

The JVM garbage collection mechanism

Objects in the heap occupy memory resources, and memory resources are limited.

Unwanted objects are garbage collected.

Garbage collection thread

The JVM itself has a garbage collection mechanism, which is a thread that runs automatically in the background.

Whenever you start a JVM process, it will come with a background thread for garbage collection.

This thread is constantly checking the JVM heap memory for instance objects in the background.

The garbage collection thread, then, will reclaim the instance object that no one points to, clearing it from memory so that it no longer occupies any memory resources.

In this case, object instances that are no longer pointed to by humans — the “garbage” in the JVM — are periodically cleaned up by the background garbage collection thread, freeing up memory resources.

How much memory does the created object occupy in the Java heap?

The memory space (heap memory) occupied by an object:

  1. The object itself
  2. The space occupied as data by instance variables of an object (containing)
  • Object headers, for example, consume 16 bytes on a 64-bit Linux operating system

  • And then if you have an instance variable of type int inside your instance object, it takes 4 bytes, and if it’s a long, it takes 8 bytes.

  • If it’s an array, a Map, something like that, then it takes up more memory

Will classes loaded into the method area be garbage collected

When is it recycled? Why is that?

Personal Thoughts:

  1. The ClassLoader corresponding to the class is reclaimed
  2. All instance objects corresponding to the class are reclaimed
  3. Class Object is no longer referenced

JVM knowledge supplement

  1. The method finishes, the reference disappears, and the heap memory does not necessarily disappear. When exporting a report, many people will create objects in the for loop, which can easily cause heap overflow.

    It is recommended that you do not create an object inside the for. You can create an object outside the for loop and modify the data of an object

  2. New instance objects are in the heap, as are instance variables

  3. If there is a parent class, how to load it?

    Loading a superclass is a superclass, and you don’t load a subclass unless you use a subclass; However, before loading the subclass to initialize, it must first load the superclass and initialize the superclass

  4. Java objects occupy memory

    Object Header (4 bytes) + Class Pointer (4 bytes) + Fields (see storage type), but the JVM memory footprint is a multiple of 8, so the result should be rounded up to a multiple of 8.

  5. Why do you have to go from class loader to class loader? Why don’t you just start at the top class loader?

    Each layer of classloader loads a class, pushes it up to the parent class loader, to the top class loader, and if it finds itself unable to load, pushes it back down to the subclass loader. This ensures that a class will never be loaded again.

    The reason why we don’t start with the top-level classloader is that the classloader itself is a parent to child model.

    If you think about a Java code implementation, its bottom subclass loader can only be found by the parent class loader it references. If you go directly to the top class loader, which is not appropriate, then wouldn’t the top class loader have to be hard-coded?

    This is a code design idea to ensure that the code is extensible.

  6. A parent delegate solves the problem of class duplication. As described in this article, each class loader has a different class load path. Is it possible that these classes will overlap?

    The paths of different classes of loaders generally do not overlap

  7. Is class initialization required to execute a static block of code and assign values to static member variables because the data is in the method area?

    Yeah, the class is in the method area, it’s in memory, so you have to initialize it, assign it

  8. An illustration of the Tomcat class loading mechanism