JVM2--JVM内存结构:类加载器、堆、栈、方法区等

本文详细介绍了Java虚拟机(JVM)的内存结构,包括类加载器的工作原理、三个阶段的加载过程,以及双亲委派机制。同时,阐述了运行时数据区的各个部分,如程序计数器、栈、堆和方法区的详细功能。此外,还讨论了类加载器的分类和它们在加载Java类时的角色。通过对JVM内存管理和类加载的深入理解,有助于优化程序性能和确保程序安全性。
摘要由CSDN通过智能技术生成

一、概述

1、知识层次

    内存结构、垃圾回收、性能调优

   

2、内存结构图

    上层:入口 class文件+类加载器

          编译器javac将java文件编译成字节码class文件

    中层:运行时数据区

         方法区----共享内存

         栈:java栈(虚拟机栈)、本地方法栈----线程私有

         程序计数器----线程私有

   下层:执行引擎:解释器、编译器(编译后端)、垃圾回收器

     

   二、类加载器---获取类的信息

  (一)三个阶段

    1、加载阶段  

        (1) 将class文件字节码加载到内存中,并生成一个这个类的Class对象

         (2)作用:.java文件生成.class文件,并在堆中生成一个Class对象

    2、链接阶段

  (1)    验证---->准备---->解析

  •    验证---语法语义问题---编译
  •    准备阶段---静态变量分配内存+置0(分配内存+给成员变量赋初始值)
  •    解析---将常量池中的符号引用替换为直接引用

                      符号引用:变量名等字面量

                      直接引用:物理地址(指向目标的指针或相对偏移量)

   (2) static final相关变量在此阶段加载(常量)

   3、初始化阶段

         开始执行类中编写的代码,进行赋真正的值

       (1)主动引用才会发生类的初始化

  •     当虚拟机启动,先初始化main方法所在的类
  •    new一个类的对象
  •   使用类的静态成员变量和静态方法(除final常量)
  •   通过反射调用类
  •   初始化一个类,会先初始化其父类

       (2)被动引用不会发生类的初始化

  • 通过子类引用父类的静态变量,不会引起子类的初始化
  • 通过数组定义类引用,不会触发此类初始化
  • 引用常量不会触发此类的初始化(常量在链接阶段就存入类的常量池了)

(二)类加载

1、类加载的作用

   将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的数据结构

   然后在堆中生成一个代表该类的Class对象,作为方法区中类数据访问入口

     

2、类加载器的作用

      将类装载进内存

3、类加载器分类

 (1)启动类加载器---加载java核心类库(JDK)

 (2)扩展类加载器---加载核心包之外的jar包

 (3)应用程序类加载器---加载class类

4、双亲委派机制

(1)原理:

        加载一个对象,首先会一层层委托给各自父类加载器,属于父类加载器加载范畴,则父类加载,否则层层下来,到谁加载谁加载

      如,自定义同名String类和核心jar包中String,会通过双亲委派机制,通过引导类加载器加载核心jar包中String

(2)优点

  • 避免类的重复加载
  • 保护程序安全,防止核心API被恶意攻击---沙箱机制

   三、运行时数据区

(一)程序计数器(PC寄存器)

     1、作用

       存储指向下一条指令的地址

       由执行引擎读取下一条指令

     2、每个线程一个,内存空间小,运行速度最快

        类似数据库结果集的游标或集合的迭代器

     3、PC寄存器存储字节码指令地址作用

          因为在多线程环境下,cpu需要不停切换给个线程,当切换回来后,就要知道从哪开始继续执行,JVM的字节码解释器需要通过改变PC的寄存器的值来明确下一条应该执行什么样的字节码指令。

(二)栈

        1、栈帧

        2、局部变量

(三)堆---分代

   1、年轻代:eden survivor: s0 +s1(年龄计数器)   8:1:1

    (1)每次new对象时,会先放在eden区

     (2)当年轻代的Eden区快满时,出发Yong GC,发生STW标记可达对象,是垃圾---清除

     (3)将其中存活的对象复制移动到s0或s1区,谁空放在谁那里(to区),

         然后遍历标记另一survivor区,垃圾清除,存活则移动到to区(复制算法 )

   (4)遍历时,form区的对象被回收超过15次依旧存活时(年龄计数器值=15),就转移到老年区

[注]:

  •  s0和s1可分为from区和to区

         谁空谁是to区,循环调换

  •    Young GC只有当eden区满的时候才会触发,survivor区满不会触发

   2、老年代:年龄值15

       老年代空间不足时先触发Major GC----还不足OOM

(四)方法区(元数据区,元空间)

    1、堆、栈、方法去的交互关系

           

     2、运行时常量池---方法区中

       (1)运行时常量池:方法区的一部分

       (2)常量池表:Class文件的一部分,用于存放编译期生成的各种字面量和符号引用

                                  这部分内容在类加载后,存放到方法区的运行时常量池中

     3、常量池        

(1) 字面量---变量的值---字符串" "或final修饰的常量值

          符号引用---变量名(而不是实际的内存地址引用)、

                         类和接口的全限定名(路径)、

                        方法的名称和描述符(修饰符、参数) 

       [注]:

  •      全类名:com.sqf.Student
  •       全限定名:com/sqf/tudent
  •       描述符:字段的数据类型、方法的参数列表、返回值

  (2)常量池=常量池计数器+常量池表

             常量池计数器---常量池容量

             常量池表---存字面量+符号引用---表-----范围[1-常量计数器值-1]       

  (3)常量池表---用符号的形式表示当前类、方法、变量的相关信息

                        ---根据这些符号可以得到相应的具体的数据类型或参数返回值类型 

             F   float类型

             I    int类型

             J   long类型

             S   short类型

              Z  boolean类型

              V  void类型

              L   对象类型,如 Ljava/lang/object  表object类型

              [    数组类型 ,如 [[D  表double [ ][ ] 

     (4)动态链接

            符号引用(变量名)-----真正的直接引用(变量地址)

四、执行引擎---逐条解释指令

1、解释器(java.exe):把高级编程语言一行一行直接转译运行

2、编译器(javac.exe):将java源程序编译成中间代码字节码文件

3、垃圾回收器(详见垃圾回收篇)

此部分参考:

简述JVM解释器与编译器的区别_静-修的博客-CSDN博客_java解释器和编译器的区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值