JVM 结构

2025-03-19  本文已影响0人  GeekAmI
1、类加载机制?

类加载指的是 JVM 通过类加载器,把.class文件加载到方法区,并在JVM堆区建一个 java.lang.Class的 实例,用来封装 Java 类相关数据和方法。一般说的类加载机制,指的是双亲委派机制,即如果一个类加载器加载了一个类,它首先不是自己去加载这个类,而是把请求委派给父加载器,以此类推...。如果父加载器加载不了,它自己才会加载,自己也加载不了就抛出ClassNotFoundException。
JVM 判定一个类是否相同有 2 个条件:1 、包+类名一致;2 、同一个类加载器加载的
类加载器从顶到下分别为 Bootstrap ClassLoader(启动类加载器)、 ExtClassLoader(扩展类加载器)、AppClassLoader(应用类加载器)

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
2、如何打破双亲委派机制?

A:继承ClassLoad抽象类,覆写loadClass方法。Tomcat 通过自定义WebAppClassLoader,优先加载Web 应用目录下的类,然后再加载其他目录下的类,进而打破双亲委派机制。具体参加:https://time.geekbang.org/column/article/105110

3、双亲委派机制的好处?

A:一是避免同类(指的同包+同名+同类加载器实例)被加载多次,二是因为优先加载父类加载器,保护 Java 核心 api的类不会被篡改。

4、类加载过程或类的生命周期?

A:类的生命周期分为 Loading(加载)、 Linking(连接)、Initialization(初始化)、Using(使用)、 UnLoading(卸载)阶段。

类加载过程分 3 步:加载->连接->初始化,其中连接过程又分为 3 步:验证、准备、解析。

类卸载过程:即该类的 Class 对象被 GC 。需满足 3 个条件:该类的所有实例都已被 GC,即堆里不存在该类的实例对象;该类没在其他任何地方引用;该类的类加载器已被 GC。

5、介绍下 Java 内存区域(运行时数据区)

A:分为线程私有区、线程共享区,线程私有区包括程序计数器、虚拟机栈、本地方法栈,线程共享区包括方法区、堆。

Q:常见概念
A:新生代垃圾回收:Minor GC/Young GC;老年代垃圾回收:Major GC;整堆垃圾回收:Full GC,回收整个堆和方法区;混合收集(Mix):Mix GC, G1中的概念,收集整个新生代和部分老年代

6、对象在堆上分配的过程?

A:情况 1:对象首先会分配到 Eden 区;情况 2:如果是大对象,直接进入老年代;如果 Eden 容纳不下,发生一次 minor GC,Eden 和 S0 一起转移到 S1区,此时仍有存活对象(S1 区),其年龄+1;下次 Eden 又满了, 发生一次minor GC,Eden+S1进入 S0,年龄又+1,当年龄大于阈值,进入老年代。

7、进入老年代的情况?

A:大对象直接进入老年代;长期存活的对象进入老年代;对象年龄动态判断,s区相同年龄的对象大小总和>s区空间一半,那么大于等于此年龄的对象进入老年代;minor GC过程中如果 S 区容纳不下,则通过分配担保机制进入老年代。

8、堆、栈、方法区的关系?

A:对象引用分配到栈,对象分配到堆,类信息存储在方法区

9、Java 对象的创建过程
10、对象的访问定位的两种方式(句柄和直接指针两种方式)
[ 栈(Stack) ]  
| 引用变量 → [ 句柄池(Handle Pool) ] → [ 对象实例数据 ]  
|          |  
|          → [ 类元数据(Class Data) ] (存储在方法区)  

图示说明:

方式 2:直接指针(Direct Pointer)

[ 栈(Stack) ]  
| 引用变量 → [ 对象头(Header) ] → [ 类元数据(Class Data) ]  
|          [ 实例数据(Instance Data) ]  
|          [ 对齐填充(Padding) ]  

图示说明:

HotSpot虚拟机使用的直接指针。

具体图例可参考:https://javaguide.cn/java/jvm/memory-area.html#%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%AE%BF%E9%97%AE%E5%AE%9A%E4%BD%8D

参考文档

上一篇 下一篇

猜你喜欢

热点阅读