JVM-02 内存模型及内存分配机制

深入理解Java的JVM内存模型 JVM内存模型定义了Java程序在执行时如何分配和管理内存。JMM的主要目的是屏蔽不同硬件、操作系统的内存访问差异,确保Java程序在各种环境下都能获得一致的执行效果。在JVM中,内存分为多个区域,每个区域负责不同类型的数据存储。这些区域大致包括方法区、堆、栈、本地方法栈和程序计数器。 阅读详情

1、JVM运行时数据区定义

初学JAVA时,对JVM中的堆、栈、方法区等甚是模糊,甚至很多老师也讲不清楚,一遍遍从概念学起太浪费功夫,今天就从官网上把JVM内存中的数据区挨个拎出来看。

1.1 运行时数据区概念

2.5. Run-Time Data Areas
The Java Virtual Machine defines various run-time data areas that are used during execution of a program. Some of these data areas are created on Java Virtual Machine start-up and are destroyed only when the Java Virtual Machine exits. Other data areas are per thread. Per-thread data areas are created when a thread is created and destroyed when the thread exits.
(Java 虚拟机定义了在程序执行期间使用的各种运行时数据区。 其中一些数据区是在 Java 虚拟机启动时创建的,只有在 Java 虚拟机退出时才会销毁。 其他数据区是每个线程。 每线程数据区在创建线程时创建,并在线程退出时销毁。)

1.2 PC寄存器

2.5.1. The pc Register
The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method (§2.6) for that thread. If that method is not native, the pc register contains the address of the Java Virtual Machine instruction currently being executed. If the method currently being executed by the thread is native, the value of the Java Virtual Machine’s pc register is undefined. The Java Virtual Machine’s pc register is wide enough to hold a returnAddress or a native pointer on the specific platform.
(Java 虚拟机可以同时支持多个执行线程(JLS §17)。 每个 Java 虚拟机线程都有自己的 pc(程序计数器)寄存器。 在任何时候,每个 Java 虚拟机线程都在执行单个方法的代码,即该线程的当前方法(第 2.6 节)。 如果该方法不是本机方法,则 pc 寄存器包含当前正在执行的 Java 虚拟机指令的地址。 如果线程当前正在执行的方法是本地方法,则 Java 虚拟机的 pc 寄存器的值是未定义的。 Java 虚拟机的 pc 寄存器足够宽,可以保存特定平台上的 returnAddress 或本机指针。)

信息解读:

  • Pc寄存器是每个线程私有的。
  • PC寄存器没有内存大小限制,不会进行垃圾清理。
  • PC寄存器的生命周期同线程的生命周期一致。
  • PC寄存器含有当前线程正在执行的方法的指令地址,遇到native方法,Pc寄存器存储的值为undefined
  • 当执行引擎从PC寄存器读取完下个指令地址后,PC寄存器的地址就会指向下一指令地址。(当执行引擎从PC寄存区读取到5后,PC寄存器的值就会指向6)。
    在这里插入图片描述

1.3 虚拟机栈

2.5.2. Java Virtual Machine Stacks
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
In the First Edition of The Java® Virtual Machine Specification, the Java Virtual Machine stack was known as the Java stack.
This specification permits Java Virtual Machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.
A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of Java Virtual Machine stacks, as well as, in the case of dynamically expanding or contracting Java Virtual Machine stacks, control over the maximum and minimum sizes.
The following exceptional conditions are associated with Java Virtual Machine stacks:
If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
(每个 Java 虚拟机线程都有一个私有的 Java 虚拟机堆栈,与线程同时创建。 Java 虚拟机堆栈存储帧(第 2.6 节)。 Java 虚拟机堆栈类似于 C 等传统语言的堆栈:它保存局部变量和部分结果,并在方法调用和返回中发挥作用。因为除了推送和弹出帧之外,Java 虚拟机堆栈从不直接操作,所以帧可能被分配到堆上。 Java 虚拟机堆栈的内存不需要是连续的。
在 Java® 虚拟机规范的第一版中,Java 虚拟机堆栈被称为 Java 堆栈。
该规范允许 Java 虚拟机堆栈具有固定大小或根据计算需要动态扩展和收缩。如果 Java 虚拟机堆栈的大小是固定的,那么在创建该堆栈时可以独立选择每个 Java 虚拟机堆栈的大小。
Java 虚拟机实现可以为程序员或用户提供对 Java 虚拟机堆栈初始大小的控制,以及在动态扩展或收缩 Java 虚拟机堆栈的情况下,控制最大和最小大小。
以下异常情况与 Java 虚拟机堆栈相关联:
如果线程中的计算需要比允许的更大的 Java 虚拟机堆栈,则 Java 虚拟机将抛出 StackOverflowError。
如果 Java 虚拟机堆栈可以动态扩展,并且尝试扩展但没有足够的内存来实现扩展,或者如果没有足够的内存可以为新线程创建初始 Java 虚拟机堆栈,则 Java 虚拟机机器抛出 OutOfMemoryError。)

信息解读:

  • 线程栈是每个线程私有的。
  • 栈的结构类似C语言的堆栈,每有方法调用后,会在当前栈中压入一个栈帧,用于存放局部变量和部分结果(操作数栈)。
  • 栈结构都是FILO,先进后出。
  • 每个线程栈有默认的大小限制,在jvm中可以使用-Xss(StackSize)配置,默认值1M(见下图)。当把Xss的值调小时,那么一个线程栈能分配的栈帧数就越少,但JVM整体能开启的线程数就更多。
  • 线程栈的大小可以设置为固定值,也可以根据需要动态扩展和收缩。
  • 当线程栈的大小固定,且线程出现超长递归或无限循环时,会出现因为超出栈内存大小的StackOverflowError报错。
  • 如果线程栈内存可以动态扩展,当遇到线程栈没有内存可用于扩展时,或新线程没有内存开辟栈空间时,就会出现OutOfMemoryError。
    在这里插入图片描述

1.4 堆

2.5.3. Heap
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor’s system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.
A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the heap, as well as, if the heap can be dynamically expanded or contracted, control over the maximum and minimum heap size.
The following exceptional condition is associated with the heap:
If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
(Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的堆。堆是运行时数据区,从中分配所有类实例和数组的内存。
堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统(称为垃圾收集器)回收;对象永远不会被显式释放。 Java 虚拟机不假设任何特定类型的自动存储管理系统,存储管理技术可以根据实现者的系统需求来选择。堆可以是固定大小的,也可以根据计算的需要进行扩展,如果不需要更大的堆,则可以收缩。堆的内存不需要是连续的。
Java 虚拟机实现可以为程序员或用户提供对堆初始大小的控制,以及如果堆可以动态扩展或收缩,则可以控制最大和最小堆大小。
以下异常情况与堆相关联:
如果计算需要的堆多于自动存储管理系统所能提供的堆,Java 虚拟机将抛出 OutOfMemoryError。)

信息解读:

  • 堆内存是所有线程共享的。
  • 堆中是存放的是类实例和数组。
  • 堆内存的生命周期:在JVM启动时创建,在运行时由GC进行回收管理,在退出虚拟机时销毁。
  • 堆内存空间可以使固定的,也可以动态扩展和收缩。
  • 当内存空间不足时,OutOfMemoryError。

1.5 方法区(元空间)

2.5.4. Method Area
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the “text” segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.
A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the method area, as well as, in the case of a varying-size method area, control over the maximum and minimum method area size.
The following exceptional condition is associated with the method area:
If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
(Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的方法区。方法区类似于传统语言的编译代码存储区,或类似于操作系统进程中的“文本”段。它存储每个类的结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化和接口初始化中使用的特殊方法(第 2.9 节)。
方法区是在虚拟机启动时创建的。尽管方法区在逻辑上是堆的一部分,但简单的实现可能会选择不进行垃圾收集或压缩它。本规范不强制要求方法区的位置或用于管理编译代码的策略。方法区可以是固定大小,也可以根据计算的需要进行扩展,如果不需要较大的方法区,可以缩小。方法区的内存不需要是连续的。
Java 虚拟机实现可以为程序员或用户提供对方法区初始大小的控制,以及在可变大小方法区的情况下,对最大和最小方法区大小的控制。
以下异常条件与方法区相关联:
如果方法区中的内存不能用于满足分配请求,Java 虚拟机将抛出 OutOfMemoryError。)

  • 方法区,又称元空间,在JDK7之前又称永久代,是线程间共享的区域。
  • 方法区类似编译代码存储区,由字节码执行引擎完整加载后存入。
  • 方法区存放运行时常量池、字段、方法、构造函数的代码等。
  • 方法区可以固定大小和动态扩展、压缩。默认无初始值。
  • 当方法区的内存大小超过MetaspaceSize阈值时,会触发Full GC,此时如收集器释放大量空间则会缩小方法区内存,如果仅释放少量空间,则会适当提高方法区内存空间。为了减少Full GC回收,一般会将MetaspaceSize和MaxMetaspaceSize都设置为256m(针对8G内存机器)

1.6 运行时常量池

2.5.5. Run-Time Constant Pool
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
Each run-time constant pool is allocated from the Java Virtual Machine’s method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.
The following exceptional condition is associated with the construction of the run-time constant pool for a class or interface:
When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.
See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.
(运行时常量池是类文件(第 4.4 节)中 constant_pool 表的每个类或每个接口的运行时表示。它包含多种常量,从编译时已知的数字文字到必须在运行时解析的方法和字段引用。运行时常量池的功能类似于传统编程语言的符号表,尽管它包含比典型符号表更广泛的数据。
每个运行时常量池都是从 Java 虚拟机的方法区(第 2.5.4 节)分配的。类或接口的运行时常量池是在 Java 虚拟机创建类或接口(第 5.3 节)时构造的。
以下异常条件与类或接口的运行时常量池的构造相关:
在创建类或接口时,如果构建运行时常量池需要的内存多于 Java 虚拟机的方法区中可用的内存,则 Java 虚拟机将抛出 OutOfMemoryError。
有关构建运行时常量池的信息,请参阅第 5 节(加载、链接和初始化)。)

1.7 本地方发栈

2.5.6. Native Method Stacks
An implementation of the Java Virtual Machine may use conventional stacks, colloquially called “C stacks,” to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine’s instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
This specification permits native method stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the native method stacks are of a fixed size, the size of each native method stack may be chosen independently when that stack is created.
A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the native method stacks, as well as, in the case of varying-size native method stacks, control over the maximum and minimum method stack sizes.
The following exceptional conditions are associated with native method stacks:
If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
(Java 虚拟机的实现可以使用传统的堆栈,通俗地称为“C 堆栈”,以支持本机方法(用 Java 编程语言以外的语言编写的方法)。本机方法堆栈也可以由 Java 虚拟机指令集的解释器实现使用,例如 C 语言。无法加载本机方法且本身不依赖常规堆栈的 Java 虚拟机实现不需要提供本机方法堆栈。如果提供,则通常在创建每个线程时为每个线程分配本机方法堆栈。
该规范允许本地方法堆栈具有固定大小或根据计算需要动态扩展和收缩。如果本机方法堆栈的大小是固定的,则在创建该堆栈时可以独立选择每个本机方法堆栈的大小。
Java 虚拟机实现可以让程序员或用户控制本地方法堆栈的初始大小,以及在可变大小的本地方法堆栈的情况下,控制最大和最小方法堆栈大小。
以下异常情况与本机方法堆栈相关联:
如果线程中的计算需要比允许的更大的本机方法堆栈,则 Java 虚拟机将抛出 StackOverflowError。
如果可以动态扩展本机方法堆栈并尝试扩展本机方法堆栈但可以提供足够的内存,或者如果可以提供足够的内存来为新线程创建初始本机方法堆栈,则 Java 虚拟机将抛出 OutOfMemoryError .)

信息解读:

  • java调用C语言实现的如native方法等,所开辟的空间。
  • 本地方发栈是线程私有的。

oracle官网的doc地址:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

2 内存模型及分配机制

在这里插入图片描述

2.1 内存回收实例动态分析:

public class HeapTest {
 	//设置100KB成员数组变量,扩大类对象在堆中的内存占用,让JVM的垃圾回收更明显
    byte[] a = new byte[1024 *100];

    public static void main(String[] args) throws InterruptedException {
    	//让main方法的成员变量成为线程栈的局部变量满足gc root要求,不能回收
        ArrayList<HeapTest> heapTests = new ArrayList<>();
        while (true){
        	//无限向线程栈的局部变量内添加对象,让gc时刻在触发
            heapTests.add(new HeapTest());
            Thread.sleep(10);
        }
    }
}

打开jdk8自带的jvisualvm.exe观察上述代码的运行结果:
在这里插入图片描述

此时,整体的运行进展与我们思考的一致。首先将对象创建到堆的Eden区,当Eden方放满时将对象放到s1区;随后eden再次放满后,将s1和eden的对象再次收集,将一部分对象放到s0,另一部分无法存放下的对象放到了老年代。
在这里插入图片描述
从程序即将OOM的图中,我们也可以看到,默认情况下,Eden区、s0、s1区的内存空间在不断的动态扩展和缩小。这最直接的显示就是图中,柱状的s区或三角状的eden区在动态的扩大或缩小。而老年代的空间由于无法回收,始终在慢慢增长,而元空间内类元信息在一开始就确定了,不会随时间变化。

检查环境中JVM的默认参数配置:

java -XX:+PrintFlagsFinal -version

2.2 方法区内存分配机制

1、JVM默认配置
首先看一下JDK8中JVM对方法区触发full GC阈值的默认设置,
在这里插入图片描述

  • 元空间默认触发full gc阈值,MetaspaceSize约为21M(gc后会动态扩展、缩小)
  • 另外MaxMetaspaceSize 最大元空间值,实际是2^64次方,换算成内存可以理解为无穷大
    2、调优
    为了减少由元空间大小触发阈值导致的full gc,从而造成的STW,所以要将元空间触发gc的默认值及元空间最大值手动设置。一般针对8G内存将上述值设置为256M。
    优化点1:
java  ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M

2.3 线程栈内存分配机制

我们最常见的线程栈问题,一般是StackOverflowError,含义即是栈溢出。
什么场景可能触发栈溢出?

  • 当线程在计算过程中需要分配比当前线程被允许拥有的最大栈空间,这是则会抛出StackOverflowError(官网解释)。
  • 当线程尚未超出被允许拥有的最大占空间,而此时内存不足了,则OOM
    在这里插入图片描述
  • 可以看到ThreadStackSize的init值是1024(注意这里的单位是K),也就是1M。
  • java ‐Xss512k(‐Xss256k)

个人理解分析:
针对线程栈的调优需要根据实际情况,具体情况具体分析。
一般来说线程栈的默认大小是没有必要进行调优的,1M可以满足除非死循环和上千次递归调用深度的需求。
但追求极致时,可以对服务接口复杂度低。线程会执行的方法不多,方法内的临时变量不多,方法内的对象不多时。我们可以适当将线程栈的大小调低,这样相同环境可以由更多的线程同时运行。

实际案例分析:

public class JvmStackDemo {
    //对比设置线程栈大小-Xss128 和默认1M,线程栈中能递归的方法次数
    static int count = 0;
    static void Recursion(){
        System.out.println(count++);
        Thread.sleep(100);
        Recursion();
    }
    
    public static void main(String[] args) {
        try {
            Recursion();
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(count);
        }
    }
}

我们发现:
默认使用1M线程栈空间时,线程内方法递归的次数达到9812次
当设置-Xss128k时,方法递归的次数是1033次
当然,这种测试只能在宏观上感受,1、线程栈的空间时有限的,2、线程栈的大小设置是可以配合需要设置的

2.4 堆内模型及分配机制

最坑爹的当然还得看堆内存,因为JVM一系列的垃圾回收机制多是为堆量身打造的。
在这里插入图片描述

2.4.1分配内存

由于类的元信息是固定的,那么类不管有多少属性信息,依次按照类成员类型就可以计算出类对象所需要占据的空间大小,此时,就要为对象在堆内划分空间。
需要划分对象的内存空间,此时以下两件事就提上日程了。

  • 1、如何划分空间?
    内存空间模型又可以分为2种,
    1.1 指针碰撞(Bump the Pointer)默认方式
    内存空间是规整有序的,碰撞指针像管理员一样,将空闲内存和已用内存分开,指针指向临界点,每次有新对象进入,指针向空闲区移动该对象的空间长度。
    1.2 空闲列表(Free List)
    如果内存空间是不规整的,那么对象又需要一块完整的区域来存放。此时,就需要虚拟机维护列表,查看哪里的空间可容纳下新的对象,塞进去。
  • 2、多线程并发划分空间怎么办?
    2.1 CAS(compare and swap)
    依赖CAS操作的原子性,将更新操作和物理内存划分的结果绑定,保证结果一致性。
    2.2 Thread Local Allocation Buffer(TLAB)本地线程分配缓冲
    简言之,堆中为每个线程预设一小块区域。当线程需要存储对象时,只要在该区域存储对象即可。
    通过­XX:+/­ UseTLAB参数来设定虚拟机是否使用TLAB(JVM会默认开启­XX:+UseTLAB),­XX:TLABSize 指定TLAB大小。
    由下图可见,JDK8是默认开启TLAB为线程开启2M的内存空间的。
    在这里插入图片描述
2.4.2 对象头

对象头包涵3个部分:

  • Mark Work(32位系统占4个字节、64位系统占8字节)。主要有锁状态、hashcode、4位的分代年龄等
  • Klass Point 。Klass Point在堆内存中实际存储的是类在元空间的类信息地址。所以32位系统使用4个字节完全足够存放该地址(32系统支持的最大内存为2^32 =4GB ),而64位系统的所能支持的内存是非常大的,但实际使用时一般16G、32G、64G完全可以使用34-36位表示,那么剩下的很大空间都是浪费的。所以JVM对这类地址进行压缩,从而得到32位信息,在寻址时再解压缩在得到原地址。
  • 数组长度
    在这里插入图片描述
 <dependency> 
 	<groupId>org.openjdk.jol</groupId> 
 	<artifactId>jol‐core</artifactId>
	<version>0.9</version> 
</dependency>

我们可以通过上述依赖包,查看对象头的实际信息。进而由开关压缩功能,展现压缩头、默认对象地址的压缩

‐XX:+UseCompressedOops 默认开启的压缩所有指针
‐XX:+UseCompressedClassPointers 默认开启的压缩对象头里的类型指针Klass Pointer

我们通过对空对象、数组、包含成员对象的类来看对象压缩前后的内存空间情况对比

public class JOLSample {
    public static void main(String[] args) {
        ClassLayout layout = ClassLayout.parseInstance(new Object());
        System.out.println(layout.toPrintable());

        System.out.println();
        ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});
        System.out.println(layout1.toPrintable());
        System.out.println();

        ClassLayout layout2 = ClassLayout.parseInstance(new A());
        System.out.println(layout2.toPrintable());
    }

    public static class A {
        //8B mark word  //4B Klass Pointer 如果关闭压缩‐XX:‐UseCompressedClassPointers或‐XX:‐UseCompressedOops,则占用8B
        int id; //4B
        String name; //4B 如果关闭压缩‐XX:‐UseCompressedOops,则占用8B
        byte b; //1B
        Object o; //4B 如果关闭压缩‐XX:‐UseCompressedOops,则占用8B
    }
}

开启指针压缩

#object对象 8位Mark word + 4位klass point + 4位补位
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

#数组[] 8位Mark word + 4位klass point +4位数组长度
[I object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     0    int [I.<elements>                             N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total


#自定义类对象 8位Mark word + 4位klass ponit + int 4位 + string 4位 + byte1位(3位补位) +object 4位  +补位4位
com.huawei.heap.JOLSample$A object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                    (object header)                           61 cc 00 f8 (01100001 11001100 00000000 11111000) (-134165407)
     12     4                int A.id                                      0
     16     1               byte A.b                                       0
     17     3                    (alignment/padding gap)                  
     20     4   java.lang.String A.name                                    null
     24     4   java.lang.Object A.o                                       null
     28     4                    (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total

如果关闭指针压缩,原有占有4位的对象都变成占8位,剩余补位。

2.5 常量池

在这里插入图片描述
在这里插入图片描述

3、对象分配过程(内存调优的重要依据)

在这里插入图片描述

3.1 对象进入Eden区

对象进入到Eden区,会提前判断。是否适合直接进入Eden,尽可能的节省空间,分配到栈上。或者把大对象直接分到老年代,节省年轻代的空间。剩余的才考虑放到Eden区什么位置,TLAB进入线程堆内存缓冲区,或者CAS直接分配

3.2 对象进入Survivor

当Eden区对象占满空间时,会触发Minor GC,此时将存活的对象放入S0区(任意)。下次Eden区再满了,再次触发Minor GC,将S0区对象和Eden区存活对象放到S1区。此时,如果因为S区剩余空间较小,触发动态年龄判断机制,将部分对象送到老年代(在进入老年代的对象里详述)。

3.3 对象进入老年代

3.3.1 大对象判断机制

当对象进入Eden区之前,通过阈值判断是否需要直接进入到老年代。

3.3.2 分代年龄机制进入老年代

当对象的Age超过阈值,一般是15岁(CMS默认6岁),将超出的对象送到老年代。

3.3.3 动态年龄判断机制

一般在Minor GC之后,S区剩余空间不多。通过计算S区Age1+Age2+Age3+AgeN 的对象空间之和 > S区总空间50%,此时提前将年龄大于N的对象送到老年代,以缓解年轻代区的压力。

3.3.4 老年代空间担保机制

每次Minor GC之前,计算老年代剩余可用空间。该空间 < 年轻代所有对象占用的空间(包括垃圾对象),说明老年代也没空间了,如果正常执行有可能会直接触发Full GC,但如果设置了老年代空间担保机制,就会计算每次进行Minor GC后放入老年代的空间是否比剩余空间大,如果平均值能放的下,那么就直接进入老年代。不设置或者放不下就FullGC。Full GC后还是没有空间存放Minor GC产生的对象,那么就OOM

JVM内存分配担保机制 目录 担保机制 案例1:新生代无法分配内存,晋升到老年代,且担保成功 结果1:使用Serial收集器 结果2:使用ParallelScavenge收集器 案例2:Parallel Scavenge晋升条件:当需要分配的内存小于等于Eden区内存的一半,就有可能让Eden区现有的对象晋升到老年代 结果 FullGC(Ergonomics) Parallel Scavenge的执行入口 Ergonomics的值 再看【need_full_gc】的值 进入【should_full... 阅读详情

相关推荐

JVM 内存模型与 JMM 内存模型

JVM 内存模型JMM(Java 内存模型)物理内存如何划分逻辑上如何安全访问共享数据关注内存分配和回收关注线程间通信和数据同步解决内存溢出、栈溢出问题解决竞态条件、内存可见性问题一句话总结:JVM 内存模型是“内存怎么用”,JMM是“多线程怎么安全地用内存”。

bentengjiayou的博客 955

JVM底层原理之栈内存Xss讲解

一、JVM常用参数 -Xms初始堆内存大小,默认物理内存64/1 -Xms = -XX:InitialHeapSize -Xmx最大堆内存,默...

lixinkuan的博客 3851

深入理解JVM内存模型与垃圾回收机制:从原理到实战调优

本文由王文峰撰写,深入探讨了JVM内存模型与垃圾回收机制,旨在帮助Java开发者解决生产环境中的内存管理问题。文章首先解析了JVM内存结构,包括Metaspace、堆内存分代和直接内存分配,接着详细介绍了对象分配与晋升机制,并对比了不同垃圾回收器的适用场景。随后,文章通过源码级解析G1收集器的内存布局、并发标记流程和记忆集优化,并结合电商平台订单系统的调优案例,展示了如何通过JVM参数调整和代码修复解决Full GC问题。最后,文章提供了性能优化进阶技巧,如逃逸分析和Shenandoah收集器的使用,并展望

王大师企业官方博客 1313

JVM常规参数

Xss-Xss1m,jdk5之后,1m。相同物理内存下,减小Xss可生成更多线程, 操作系统对一个进程内的线程数是有限制的,不能无限生成,经验值在3000~5000左右。: 功能等同于-Xss,默认=0,表示使用默认的一般只使用Xss即可。

qq_25775675的博客 6813

OPCUA二(通过OPCUA服务器访问CPU)

摘要:本文介绍了使用UaExpert软件连接西门子PLC的OPC UA配置方法,包括IP地址设置(默认端口4840)、安全认证和证书信任流程。详细说明了数据访问操作,如变量拖拽监控和属性解读(NodeId、Value、状态码等)。特别强调连接仿真Advance7时需先启动实例。最后预告下章将讲解通过KerServer访问CPU。文章涵盖配置步骤、常见问题处理及实用技巧,适合工业自动化开发者参考。

欢迎来到RaymondLeigh的知识共享基地 1340

Playwright Java环境配置避坑指南:浏览器路径、类加载与离线部署

Playwright作为现代端到端测试框架,其Java SDK突破了传统Selenium的Driver管理模式,将Chromium/Firefox/WebKit内核视为可编程运行时资源。其核心原理在于SDK与浏览器二进制分离——Maven仅管理Java字节码,而浏览器需独立下载、校验与沙箱加载。这一设计带来显著技术价值:跨平台一致性、进程隔离安全性及多浏览器并行能力;典型应用场景涵盖Spring Boot集成测试、金融级离线CI/CD、Kubernetes容器化部署及Air-Gapped封闭环境。然而,因J

weixin_32956805的博客 678

JVM的默认内存是怎么分配的?

当运行java程序出现OOM问题时,其实第一个想到的解决方法就是 增加机子内存,但是很简单的将机子内存由4G升级到了8G,这时就会成功运行java程序。为什么简单的增大了内存就会做到这一点呢?我又没有修改jvm的参数。,但是默认是关闭的然后通过命令,查看jvm的默认堆大小。当我把虚拟机内存调整为4G时调整为8G时。...

m0_67403076的博客 1051

【机器人】机械臂控制入门技术栈分享

机械臂控制入门技术栈分享1.前言2.机器人控制入门技术栈2.1.空间描述和变化2.2.运动学分析2.3.动力学建模2.4.控制入门学习3.进阶部分3.1.机器人参数辨识3.2.非线性控制3.3.现代机器人描述方法:指数坐标4.总结 1.前言 今天看到优快云上有个分享个人技术栈的活动,虽然我不是一个正规的程序员,也不搞前端、后端这些,但我一直在优快云上通过写博客对我的学习进行总结,于是我突发奇想,不如我也写一下我的个人技术栈,针对机械臂控制入门的,因为我水平也不高,所以本文内容也许不够饱满,也不够准确,但

要恰饭得嘛 5858

JVM参数及默认值

Java启动参数共分为三类其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容;其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容;其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用;

m0_67401417的博客 2293

Allegro如何设置走线自动删除重复走线操作指导

Allegro如何设置走线是自动删除重复走线操作指导在PCB布线的时候,点到点需要重复走一段线的时候,希望原来的线段自动被删除,Allegro设计的时候支持这个操作如下图,重复走中间的线段的时候,希望下方的走线自动删除具体操作如下This section is describe what the function allegro have ,helpfully could let user know more about allegroAllegro Design and Analysis includes

weixin_54787054的博客 4499

6.6kW的车载充电器(On-Board Charger, OBC)电路分析

图片展示了6.6kW的车载充电器(On-Board Charger, OBC)电路,其中包含双向和单向两种拓扑结构。接下来我们将深入分析每个模块的设计、原理及其优势,以帮助理解不同结构在实际应用中的选型和应用。

weixin_43199439的博客 5665

JVM常用基础参数栈内存Xss讲解

JVM常用参数 -Xss 参数为设置单个线程栈的大小, 一般默认为512K~1024K 其等价于 -XX:ThreadStackSize 栈是用来运行方法的, 堆是用来存储数据. 通过此程序查看栈内存大小 public class MyHelloGc { public static void main(String[] args) throws InterruptedException...

Java持续实践 4918

SAP Fiori Launchpad 上看不到任何 tile 应该怎么办?

中心UI组件是一个框架,为所有SAPFiori应用程序提供公共基础设施SAPFiorilaunchpad是所有SAPFioriUI的基础,并为SAPFiori应用程序提供基本功能,如登录,界面大小,应用程序之间的导航,和基于角色的应用程序目录。ABAP前端服务器包含所有基础设施组件,用于为客户端生成SAPFiori应用程序特定的UI,并与SAPBusinessSuite后端系统通信。SAPFiori应用程序的处理过程如下首先,客户端加载SAPFiori应用程序的界面。...

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 942

JVM内存模型与类加载机制

JVM内存模型与类加载机制(以前的笔记)

分享学习编程中的遇到的问题,总结平时的笔记 3338

pyecharts在jupyter notebook中不能够渲染图表问题。

在使用jupyter notebook中使用pyecharts绘制可视化图表的时候,发现图表不能渲染到页面中,生成的html是没问题的,本文主要解决在jupyter notebook中不能渲染这个问题。

猿小白的博客 1167

【新能源汽车测试工程师必看!DBC文件50条实战技巧,看懂这篇直接封神】

如果你是新能源汽车研发/测试工程师,还在为信号解析错误、报文找不到、DBC看不懂、实车故障复现不了头疼——那这篇文章,你一定要!在整车电控开发里,DBC = CAN总线的官方字典。没有DBC,报文就是一串乱码;读不懂DBC,测试寸步难行;用不好DBC,排查故障全靠猜。本文总结50条全网最实用、最贴近实车、最能解决问题的DBC技巧,从基础语法到新能源专用信号,从工具操作到故障排错,全部来自一线台架、实车、高压平台实战经验。不废话、不空谈、不玄学,全是能直接落地的硬货!

优快云-新能源汽车研发测试专业博主 1372

JVM内存划分、JVM内存分配机制、JVM垃圾回收机制

--------------------------------------------------- JVM内存管理分为两部分: 内存分配 内存回收 ------------------------------------------------------ 内存回收经常也被叫做垃圾回收。(附带资料:JVM面试题超链接、JVM性能调优和 参数说明) *很多人迷惑一个问题,既然J...

此处省略三千字 1万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

JVM 内存模型与内存分配方式

详细介绍了 JVM 内存模型,与内存划分方法、内存划分并发问题的解决方案、对象栈上分配、基于分代收集理论的垃圾收集器管理下的堆内存分配规则等知识点。

Bryant5051的博客 636

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

JVM初探 -JVM内存模型

JVM是每个Java开发每天都会接触到的东西, 其相关知识也应该是每个人都要深入了解的. 但接触了很多人发现: 或了解片面或知识体系陈旧. 因此最近抽时间研读了几本评价较高的JVM入门书籍, 算是总结于此. 本系列博客的主体来自 深入理解Java虚拟机(第二版) 和 实战Java虚拟机 两部书, 部分内容参考 HotSpot实战 和 深入理解计算机系

菜鸟-翡青 5万+

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Java核心篇之JVM探秘:对象创建与内存分配机制

Java虚拟机(JVM)是Java语言的核心组件之一,负责执行Java字节码。在JVM中,对象的创建和内存管理是一个复杂而精细的过程,涉及多个阶段和多种策略。本文将深入探讨JVM中的对象创建流程、内存分配机制以及它们如何影响程序性能。JVM中对象的创建和内存分配是一个多步骤、多策略的过程,涉及类加载、内存布局、垃圾回收等多个层面。理解和优化这一机制对于提升Java应用程序的性能至关重要。通过合理的设计和编码实践,我们可以最大限度地发挥JVM的优势,构建高效稳定的应用系统。

小码农的博客 3157

JVM内存模型与内存分配机制

JVM内存模型与内存分配机制 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。new指令对应到语言层面上讲是,new关键词、对象克隆、对象序列化等。

shuaime的博客 214

JVM内存分配机制

Java虚拟机最重要的工作就是如何给对象分配内存空间,以及通过GC如何回收已经不再使用的内存空间。这篇文章主要介绍JVM中的Java对象是创建过程、对象内存的分配机制以及对象内存的回收机制。 一、对象的创建 在前面的文章《JVM类加载机制》中讲过,JVM中所有对象的创建,都需要先将对应的.class文件加载进内存,所以JVM中通常一个对象的创建包含了如下几个步骤: 1.1 检查类是否加载 当JVM执行到new字节码指令时,首先会去运行时常量池检查该指令指定的参数能够找到对应类的符号引用,并检查这个符号引用

sermonlizhi的博客 3781

聊聊JVM的内存模型

JVM内存模型定义了Java程序运行时的内存组织结构和管理机制。它不仅是内存分配的基础,更是程序执行、垃圾回收、多线程并发的基石。这里需要分清一个点,JVM和JMM(Java内存模型)是两个完全不同的概念Java内存模型(JMM):Java语言层面的内存模型,关注多线程环境下的内存可见性、原子性、有序性JVM内存结构(运行时数据区):JVM进程在执行Java程序时的内存布局和管理机制1.分层设计:线程私有与共享区域分离,平衡性能与安全性2.分代管理:基于对象生命周期优化垃圾回收3.自动管理。

gdpu2400502251的博客 1365

JVM内存模型和结构

JVM简介:JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、 一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接的交互。 JVM内存模型结构图::: 1.JVM内存模型和结构 (1)JVM内存模型如下::: Young(年轻代)= New Tenured(老年代)= Old Perm(永久代) = Perm Young(年轻代)可以分为Eden区和两个Survivor区(from和to,这两个Survivor区大小严格一致),新

m0_67391907的博客 7198

JVM-深入理解JVM内存模型、类加载机制、内存分配机制

运行该段代码,查看大体流程,如图其中loadClass的类加载过程分为:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载1.通过类型的完全限定名,产生一个代表该类型的二进制数据流(没有指明从哪里获取、怎么获取,是一个非常开放的平台),加载源包括:文件(Class文件,jar文件)、网络、计算生成(代理$Proxy)、由其它文件生成(jsp)、数据库中;2.将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构;

earlybird_xiong的博客 670
上一篇: JVM-01 类加载过程及源码分析
下一篇: JVM-03 垃圾收集器
旧梦昂志
博客等级 码龄7年 3724粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧梦昂志

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值