JVM Study Notes (2) – The structure of the JVM

Structure map 0.

1. Runtime data area overview

  1. Class loading subsystem: The loaded class information is stored inMethods areaIn the middle,Methods areaIt may also include run-time constant pool information, including literal string and numeric constants.
  2. The Java heap: The heap is created when the virtual machine starts and is the primary memory working area for Java programs.Almost all Java object instances are stored in the Java heap, heap space is shared by all threads, a piece of memory closely associated with Java applications.
  3. Java stack: is the private memory space of each thread,JavaThe stack is closely related to thread execution. The basic behavior of thread execution is the call between functions, and the data of each function call is passed by the Java stack. In the Debug interface of Intellij Idea, we can see the stack information:

One of the items is called a stack frame. A stack frame contains at least several parts of the local variable table, operand stack, and frame data area. When a function returns, the stack frame is ejected from the Java stack. (Returns include return and exception)

  1. Local method stack: Local refers toNative, the JVM allows Java to call native methods directly.
  2. PC: Program CounterProgram counter“Is the same as the PC in the CPU, where the Java code is currently going. A Java thread is executing a method. The method being executed is called the current method, or if the current method is not a native method, it points toThe command being executedIf a local method is executed, then the value of the PC register is undefined.
  3. Execution engine: is one of the core components of the Java virtual Machine. It is responsible for executing the bytecode of the virtual machine. Modern virtual machines use just-in-time compilation techniques to compile methods into machine code before executing.

In fact, we can see that the gray areas (Java stack, local method stack, program counter) are thread private, while the rest of the space is thread shared.

2.PC, local method stack, Java stack

All three are thread private.

PC program counter

The PC register is used to store the address to the next instruction, and also the code of the instruction to be executed, which is read by the execution engine. It is a small memory space, almost negligible, and the fastest area of storage. In the JVM specification, each thread has its own program counter, which is thread private and whose life cycle is consistent with the thread cycle.

The PC register is an indicator of the program control flow. Branches, loops, jumps, exception handling, thread recovery and other basic tasks depend on it.

It is the only area in the Java Virtual Machine specification that does not specify any OOM conditions. There is also no GC region.

Java stack

Each time a function is called, a separate stack frame is maintained on the call stack. The stack frame generally includes:

  1. Local variable table: a set of variable value storage space used to store method parameters and local variables. VMS use the local variable table by indexing. The store includes eight basic data types, reference addresses of objects, and calls and returns of participating methods.

  2. Operand stack: deposit method call argument, namely the operands (in each stack frame in the conceptual model are independent of each other, but the actual implementation, will make two separate stack frame part of overlap, the following part of the operand stack and overlap of the local variables in an area, it can share part of the data in the method invocation.) .

  3. Dynamic linking :(omitted, which is actually a method reference to a run-time constant pool).

  4. Method return address: The return of a method is divided into two cases:

    • The first is to support exit, which determines whether to pass the return value to the upper caller according to the method definition.
    • The other is the end of the method due to an exception, which does not involve the return value being passed to the calling method above.

When you exit a method, whether it’s an exception or a normal one, you exit at the original call.

  1. If it is a normal exit, then the caller’s PC register is the return address.
  2. If it is an exception exit, refer to the exception handling table to determine.

Local method stack

Native methods are intrinsically implementation-dependent, and designers of virtual machine implementations are free to decide what mechanism to use to get Java programs to call native methods.

3. The Java heap

There is only one heap memory per JVM, and the heap is the core area of Java memory management. It is created when the JVM virtual machine is created, its size is determined, and it is the largest chunk of memory managed by the JVM. The heap is not physically required to be continuous, but it is logically required to be. All threads share the Java heap, and you can divide thread-private buffers in the heap.

Pre-java 7 heap memory separation

The new generation + the old generation + the permanent generation

Heap memory separation in Java 8 and beyond

Divided into: new generation + old age + meta space

1. Memory partition and an important function of the JVM: GC (garbage collection) has a very large relationship, different objects, different areas of the object GC collection frequency is different, mainly refer to the GC algorithm. 2. The objects created by us (quite a lot of them are temporary objects) are stored in the new generation and can be collected in a relatively short time. If they are not collected, it means that the objects are used relatively frequently and cannot be collected by MULTIPLE GC. Permanent generations are used to store classes, run-time constant pools, fields, methods, code, JIT code, and so on. 3. What is the relationship between permanent generation and method area? A permanent generation is an implementation of the method area. It is part of the JVM specification that Class objects generated after Class loading are placed in the method area, but it does not say that a memory called the method area must be created. In fact, we chose to build the method area in the permanent generation to store these objects. Not all virtual machines have a permanent generation, we are using HotSpot in the JVM virtual machines existed only before JDK7, JDK8 and later was replaced by MetaSpace. 4. What is the relationship between GC algorithm and heap memory partition? The GC algorithm mainly determines whether the object has the value of survival according to a series of rules. Releasing irrelevant objects in time can save space. The partition of heap memory is related to the frequency of GC, and the GC algorithm within each partition is different.

  • Cenozoic: GC frequency is relatively high.
  • Old age: The FREQUENCY of GC is relatively low.
  • Permanent generation: mainly GC some unloaded classes and discarded constants.

4. Run the engine

Once the bytecode is read into the JVM, the machine cannot read it. Only the JVM can read it, so the JVM must do one thing: translate the JVM into machine code for the relevant platform (01), which is not covered in this chapter. Here’s a look at the JIT technology and AOT technology used in Android. The former is dynamic compilation and the latter is static compilation.

Just-in-time compilation

Early Android (Android 2.1 and before) applications executing Java code actually had the interpreter translate each Java instruction into several equivalent microprocessor instructions and execute them one at a time in order according to the translated instructions. Execution in this way requires translation before execution, which is predictably inefficient.

With the introduction of JIT technology since Android2.2, the technology simply states that every time a Class file is encountered, the JIT compiles the Class, producing a fairly compact binary code that takes a little time to compile in exchange for faster subsequent execution. The introduction of JIT was a big performance boost, but it was very limited. Because some Java files are rarely executed, compiling them can take much longer than the translator takes to translate them. Overall, the time spent did not decrease.

Later, based on JIT experience, a dynamic compiler is proposed to dynamically predict what needs to be compiled and what needs to be translated, so a dynamic compiler includes both a compiler and an interpreter.

After compilation, Java files are all ByteCode files, no matter in traditional JVM, Dalvik or ART virtual machine. However, the composition of Bytecodes in different virtual machines is different. Where, the corresponding runtime file for the JVM is. Class files, whereas Dalvik corresponds to.dex files, DVM is specifically optimized for mobile operating system features and is designed based on registers. The instruction set is quite different. (For a register-based design, refer to RISC: A Reduced-instruction system computer with fewer and more critical instructions that relies more on registers for faster speed and lower power consumption.)

AOT(Ahead-Of-Time)

Ahead – Of – Time technology.

ART mode (Android Runtime) first appeared as an optional feature in Android 4.4’s developer options. As an alternative to Davlik, ART is compiled at installation, and the compiled file is not a bytecode, but a concrete executable. You can run on lower-level hardware, which saves precompilation and translation time at run time. The executable file is essentially an ELF file (which is used for binary, executable, object code, shared library, core dump). On Android, there are no explicit OAT files. OAT files are still suffix. The ELF header can be seen by opening file or UE.

ART is designed with compatibility in mind, and even Dex files from earlier compiled Android projects can be used on Android devices running in ART mode. This is achieved by dex2OAT. Dex and odex files under Dalvik can be converted into OAT files through this tool, and odex files will be compiled faster than dex files.

The most obvious benefit of decodex is that when the system is first booted, the Dex file needs to be extracted from all the APK files, while Odex optimization is extracted in advance, so that the speed of running and booting is improved. Secondly, after Odex optimization, there can be no Dex file in APK, but there is a Dex file in APK package for Odex, and another one is extracted under /data/dalvik-cache, which wastes storage space. To some extent, it protects the hardware vendor’s own APK, since APK only contains resource files and disassembly makes no sense. The specific code is in the Odex.

It is precisely because of AOT technology that the machine with Android 5.0 system is very slow to boot after initialization or initial boot, because the system will extract the dex bytecode of all apps, optimize it and copy it to the /data/dalvik-cache directory. Therefore, the time for the first boot will be significantly higher.

In Android 7.0, JIT has been re-enabled, using a mixed AOT/JIT compilation strategy, which features:

  1. Dex is no longer compiled when the application is installed
  2. When the App is running, the dex file is directly executed through the parser, and the hotspot functions are identified and compiled by the JIT and stored in the JIT Code cache. A profile file is generated to record the information of the hotspot functions.
  3. When the phone is in IDLE or Charging state, the system scans the profile file in the App directory and executes the AOT procedure to compile it.
Reference source

A brief introduction to the Java JVM heap space

  1. Talk about Dalvik, ART and JIT, AOT on Android