JVM基础

一、JVM概述

虚拟机

        在windows中,虚拟一个运行环境
        分为系统虚拟机VMware,程序虚拟机JVM

jvm作用

        负责将字节码加载到内存中(运行时数据区)
        负责存储数据
        把字节码翻译为机器码,执行
        垃圾回收

jvm组成部分

        1.类加载器(负责加载字节码文件)
        2.运行时数据区(存储时数据,堆,java虚拟机栈(运行java自己的方法),方法区,程序计数器,本地方法栈)
        3.执行引擎(更底层,把字节码翻译为机器码)
        4.本地方法接口
        5.垃圾回收

二、类加器

作用

        负责从硬盘/网络中加载字节码信息
        加载到内存中(运行时数据区的方法区中)

类加载过程

        加载

                使用IO读取字节码文件
                转换并存储,为每个类创建一个Class类的对象
                存储在方法区中

        链接(验证,准备,解析)

                验证:对字节码文件格式进行验证,文件是否被污染
                         对基本的语法格式进行验证
                 准备:为静态的变量进行内存分配
                          public static int value = 123; value 在准备阶段后的初始值是0,而不是123
                          静态常量在编译期间就初始化
                  解析:将符号引用转为直接引用
                          将字节码中的表现形式,转为内存中表现(内存地址)

         初始化

                        类的初始化,为类中定义的静态变量进行赋值

                        public static int value = 123; value 在初始化阶段后的初始值是123.

类什么时候会被加载(初始化)

                1.在类中运行main方法
                2.创建对象
                3.使用类中的静态变量
                4.反射Class.forName("类的地址");
                5.子类被加载
                    以下两种情况类不会被初始化

        static finall int b = 20;//编译期间赋值的静态常量
            System.out.println(User.b)
            User[] user = new User[10]; 

类加载器

        具体的负责加载类的一些代码

        1.引导类加载器,用c/c++语言开发的,jvm底层的开发语言,负责加载java核心类库.
            与java语言无关的.
        2.扩展类加载器
            java语言编写的,由 sun.misc.Lanucher$ExtClassLoader 实现,继承ClassLoader类
            从JDK系统安装目录的jre/lib/ext子目录(扩展目录)下加载类库
        3.应用程序类加载器
            java语言编写的,由 sun.misc.Launcher$AppClassLoader 实现,派生于ClassLoader类
        4.自定义类加载器

双亲委派机制

        加载一个类时,先委托给父类加载器,如果父类加载器还有父类,就继续向上委托,直到引导类加载器父级找到就返回,父级如果最终没有找到,就委派给子级加载器最终没有找到,报 ClassNotFoundException.
        为了先确保加载系统类  
        双亲委派机制,是Java提供的类加载的规范,但不是强制不能改变的。 我们可以通过自定义的类加载器,改变加载方式。

打破双亲委派机制

        可以通过继承ClassLoader类,重写loadClass/findClass方法。实现自定义的类加载。典型的tomcat中,加载部署在tomcat中的项目时,就使用的是自己的类加载器

三、运行时数据区

1.程序计数器

        是一块很小的内存空间,用来记录每个线程的指令位置,
        是线程私有的,每个线程都拥有一个程序计数器,生命周期与线程一致
        是运行时数据区中,唯一一个不会出现内存溢出的空间
        运行速度最快

2.本地方法栈

        用来运行本地方法的区域
        是线程私有的
        空间大小可以调整可能会出现栈溢出

3.java栈

        基本作用特征

                栈是运行单位,管理方法的调用运行
                是用来运行Java方法的区域。
                可能会出现栈溢出。
                是线程私有的

        运行原理

                先进后出的结构
                最顶部的称为当前栈帧

        栈帧结构

                一个栈帧中包含:
                        局部变量表(存储在方法中声明的变量)
                        操作数栈(实际计算运行)
                        动态链接

 String name;
     void A(){
        B();//B方法的地址
    }


                        方法返回地址

4.堆

        基本作用特征

                是存储空间,用来存储对象,是内存空间最大的一块区域,
                在Jvm启动时就被创建,大小可以调整
                本区域是存在垃圾回收的,是线程共享的区域

        堆空间的分区:

                年轻代(新生区/新生代)
                        伊甸园区(对象刚刚创建存储在此区域)
                        幸存者1区
                         幸存者2区
                 老年代(老年区)

        为什么要分区

                可以根据对象的存活的时间放在不同的区域,可以区别对待
                频繁回收年轻代,较少回收老年代。

        创建对象,在堆内存中分布

                1.新创建的对象,都存储在伊甸园区
                2.当垃圾回收时,将伊甸园中垃圾对象直接销毁,将存活的对象,移动到幸存者1区
                3.之后创建的新对象还是存储在伊甸园区,再次垃圾回收到来时,将伊甸园区中的存货对象移动到幸存者2区,同样将幸存者1区的存活对象移动待幸存者2区,每次保证一个幸存者区是空的,相互转换
                4.每次垃圾回收时,都会记录此对象经历的垃圾回收次数,当一个对象经历过15次回收,仍然存活,就会被移动到老年代   垃圾回收次数,在对象头中有一个4bit的空间记录,最大值只能是15.
                5.老年区回收次数较少,当内存空间不够用时,才会回收老年代

        堆空间的配置比例

                默认的新生代与老年代的比例:1:2  可以通过 -XX:NewRatio=2 进行设置
                如果项目中生命周期长的对象较多,就可以把老年代设置更大
            
                在新生代中,伊甸园区和幸存者区比例:8:1:1
                可以通过 -XX:SurvivorRatio=8进行设置
                对象垃圾回收的年龄 -XX:MaxTenuringThreshold=<N>

        分代收集思想   Minor GC、Major GC、 Full GC

                对年轻代进行垃圾回收成为 Minor GC/yong GC 是频繁进行的回收
                对老年代进行垃圾回收称为Major GC/old GC 回收的次数较少
                Full GC 整堆收集  尽量避免:
                        System.gc();时  程序员几乎不用
                        老年区空间不足
                        方法区空间不足

        堆空间的参数设置

                官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html                 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

        字符串常量池

                在jdk7之后,将字符串常量池的位置从方法去移动到了堆空间中,
                因为方法去的回收,在整堆收集时发生,回收频率低
                堆空间回收频率高

5.方法区

                作用:主要用来加载存储的类信息,以及即时编译期编译后的信息,以及运行时常量池

                特点:在jvm启动时创建,大小也是可以调整的,是线程共享,也会出现内存溢出

        方法区,堆,栈交互信息

                方法去存储类信息(元信息)
                堆中存储创建的对象
                栈中存储对象引用        

        方法区大小设置

                -XX:MetaspaceSize 设置方法区的大小
                windows jdk默认的大小是21MB
                也可以设置为-XX:MaxMetaspaceSize 的值为-1,既没有限制,没有限制,就可以使用计算机内存
                可以将初始值设置较大一点,减少了FULL GC 发生

        方法区的内部结构

                    类信息
                    即时编译期编译后的信息、
                    运行时常量池(指的就是类中各个元素的编号)

        方法区的垃圾回收

                在FULL GC 时方法区发生垃圾回收
                主要时回收类信息,类信息回收条件比较苛刻,满足一下3点即可
                1.在队中,该类及其子类的对象都不存在了
                2.该类的类加载器不存在了
                3.该类的Class对象不存在了
                也可以认为类一旦被加载就不会被卸载了

特点总结

                程序计数器,java栈,本地栈是线程私有
                程序计数器不会出现内存溢出
                Java栈,本地栈,堆,方法区可能会出现内存溢出
                Java栈,本地栈,堆,方法区大小是可以调整
                堆,方法区是线程共享的,是会出现垃圾回收

四、本地方法接口

        什么是本地方法

                用native关键字修饰的方法,没有方法体

        为什么用本地方法

                java语言需要与外部的环境进行交互(例如需要访问内存,硬盘,其他的硬件设备),直接访问操作系统的接口即可
                java的jvm本身开发也是在底层使用到了C语言

五、执行引擎

        作用:将加载到内存中的字节码(不是直接运行的机器码),解释/编译为不同平台的机器码

        .java---编译--->.class 在开发期间,有jdk提供的编译器(javac)及进行源码编译(前端编译)
        .class(字节码)---解释/编译--->机器码(后端编译,在运行时,由执行引擎完成的)

        翻译器:将字节码逐行解释执行,效率低

        编译器:(JIT just in time 即时编译器):将字节码编译,缓存起来,执行更高效,不会立即使用编译器,将一些频繁执行的热点代码进行编译,并缓存到方法区中,以后执行效率提高了

        程序启动后,先使用解释器立即执行,省去了编译时间
        程序运行一段时间后,堆热点编译进行缓存,提高后续执行效率
        采用的解释器和编译器结合的方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值