JVM 相关知识

一、JVM内存
以java1.8为例
必会!自己说出JVM内存中有哪些部分

1.运行时区域:
线程共有的:堆,线程独自有的:虚拟机栈,pc,本地方法栈(存放native方法)
堆中有: 字符串常量池,静态变量,
堆可以分为新生代、老年代、元空间
2.本地内存:
方法区和直接内存区

方法区是一个概念性的抽象,其实现有,元空间(有运行时常量池(字符串常量的符号引用等),方法区作用:将加载的Class文件中的类信息、字段信息、方法信息、常量、静态变量、符号引用等数据,存储到方法区中!!

举例:

package com.example;

// ① 类的完整名称、父类、接口等元数据信息
public class Demo {
    
    // ② 运行时常量池中的符号引用和常量
    public static final String CONST_STR = "Hello, Method Area";  
    public static final int    CONST_INT = 100;                  

    // ③ 静态变量(存放在方法区,对应内存中有实际存储空间)
    public static int counter = 0;                                
    private static Object sharedObj;                              

    // ④ 实例变量(存放在堆中,每实例一份)
    private int id;                                              
    private String name;                                         

    // ⑤ 静态初始化块(<clinit> 方法的一部分,在类初始化时执行)
    static {
        sharedObj = new Object();
        counter = 10;
    }

    // ⑥ 构造器和普通方法的字节码(方法区存储方法元数据和字节码)
    public Demo(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public void sayHello() {
        System.out.println(CONST_STR + ", I'm " + name);
    }

    // ⑦ 静态方法字节码也存放在方法区
    public static void resetCounter() {
        counter = 0;
    }
    public static void main(String[] args) {
            Demo d = new Demo();
            d.sayHello();      // ← 这里就是一个符号引用 to com.example.Demo.sayHello:()V
        }
}

Constant pool:
#10 = Methodref          #3.#17         // com/example/Demo."<init>":()V
#11 = Methodref          #3.#18         // com/example/Demo.sayHello:()V
#17 = NameAndType        #19:#20        // "<init>":()V
#18 = NameAndType        #21:#22        // "sayHello":()V
#19 = Utf8               <init>
#20 = Utf8               ()V
#21 = Utf8               sayHello
#22 = Utf8               ()V
   ...

其中#11 = Methodref #3.#18 就是一个 符号引用,指向常量池中表示类索引 #3(com/example/Demo)和名字/描述符索引 #18(sayHello()V)的项。

在字节码中,调用 d.sayHello() 会编译为一条 invokevirtual #11 指令。

动态链接(解析)流程:
执行到 invokevirtual #11
JVM 首次遇到这条字节码时,看见常量池索引 #11,发现还没被解析。
解析阶段(Resolution)
JVM 查找常量池里 #11 指向的符号引用:
拿到类索引(#3 → com/example/Demo),确保该类已加载、已验证、已准备;
拿到名字/描述符索引(#18 → sayHello:()V),在 Demo 的方法表中查找对应方法。
查到后,JVM 会在运行时常量池的这个槽位(#11)上缓存一个直接引用(通常是指向方法区里 Demo.sayHello 方法实现的入口点、或者是一张跳转/虚方法查找表中的索引)。
后续调用
下一次再遇到 invokevirtual #11,JVM 不再去查符号引用,而是直接跳转到缓存好的本地代码地址(或通过 vtable 一次间接跳转),省去了符号解析开销。

二、JVM垃圾回收

  1. 与堆密切相关
    堆中存放着对象,(对象头、实例数据、填充)
    对象头
    Mark Word:存储对象的运行时数据,如哈希码(hashCode)、GC 分代年龄、锁信息(偏向锁、轻量级锁、重量级锁)等。
    Class Pointer(也叫 Klass Word):指向对象的类型元数据(方法区/元空间中的类结构),用来支持类型检查、方法调用等。

实例数据(Instance Data)
也就是你在类中定义的各个实例字段(非 static 的字段)。
对于继承关系,父类的实例字段会先于子类字段排列。

对齐填充(Padding / Alignment)
HotSpot 为了提高访问效率,会把对象大小向 8 字节边界(或更高、视架构而定)对齐。

  1. 可达性分析算法
    首先明确:小对象1先放入新生代区中,当后续再new一个对象时检查新生代区是否满,满了则发起一次 Minor GC,将原始的小对象1存入老年代区;没满的话小对象1的年龄+1,当它的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中
    大对象(比如:字符串、数组)直接放入老年代区

可达性分析算法思想:

Object 6 ~ Object 10 之间虽有引用关系,但它们到 GC Roots 不可达,因此为需要被回收的对象。
哪些对象可以作为 GC Roots?

3.垃圾回收算法:
(1)标记清除

(2)标记复制

(3)标记整理

(4)分代收集
根据各个年代的特点选择合适的之前的某种收集算法中。

posted @ 2025-06-15 19:58  torrentgz  阅读(3)  评论(0)    收藏  举报