Java虚拟机学习笔记

一、JDK、JRE和JVM

JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib合起来就称为jre。

JRE(Java Runtime Environment,Java运行环境),包含JVM标准实现及Java核心类库。JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)。

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

总结:JDK是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。JRE是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。JVM是整个java实现跨平台的最核心的部分,能够运行以Java语言写的程序。

二、为什么有必要学习JVM

        Java程序无需显示分配和回收内存,由JVM自动管理内存的分配及回收,给开发人员降低了编写程序的难度, 副作用是可能在不知不觉中浪费了很多内存, 导致JVM花费很多时间进行内存回收, 另外由于不清楚JVM内存的分配和回收机制, 有可能造成内存泄露. 因此JVM如何进行内存的分配和回收也是要关注的问题。

        开发过程中经常遇到OutOfMemory、Stack Overflow此类的异常,需要了解Java内存分配,JVM运行时候的规则才能清楚为什么会发生,怎么去避免出现这样的问题。

三、JAVA内存结构及垃圾收集


    1)堆内存  分为老年代和年轻代;年轻代分为Eden区、From Survivor和To Survivor


    2)方法区 是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等,存储类信息,常量、静态变量等数据,是线程共享的部分。
        也存在垃圾收集如废弃常量和无用的类。
                无用的类是指:该类所有实例已被回收;加载该类的classLoader已经被回收;该类的对应的Java.lang.class对象没有任何地方被引用
    3)栈 分为Java虚拟机栈和 本地方法栈
            Java虚拟机栈描述JAVA方法执行的内存模型;本地方法栈为虚拟机使用到的Native方法服务

    4)程序计数器 是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器
    5)内存分配规则
        1、对象优先在Eden上分配
        2、长期存活的对象将进入老年代
            -XX:MaxTenuringThreshold此参数类增到15的时候进入老生代
        3、大对象直接进入老年代
        4、动态对象年龄判断
            在survivor空间中相同年龄所有对象的大小的总和大于survivor空间的一半,这些对象直接进入老生代
        5、空间分配担保

     6)Java虚拟机运行原理
      1、对象的创建:类加载检查、分配内存、将分配到的内存空间初始化为零值、init
      2、对象的内存布局:对象头(存储对象自身的运行时数据和类型指针)、实例数据(对象真正存储的有效信息)、对齐填充
      3、对象的访问定位:句柄访问和直接访问
        句柄访问最大好处:reference中存储的是稳定的句柄地址,对象移动时只会改变句柄的实例数据指针,reference本身不需要改变
        直接访问速度更快,节省了一次指针定位的时间开销,访问频繁导致指针执行成本增加

     7)垃圾回收判断对象是否已死?

  1、Java引用分类

    强引用

        垃圾收集器永远不会回收掉被引用的对象

    软引用

        在发生内存溢出异常之前二次回收,如果还没有足够内存,则抛出内存溢出异常

    弱引用

        关联对象只能生存到下次垃圾收集之前

    虚引用

        仅在这个对象被回收时收到一个系统通知

2、引用计数算法:很难解决对象之间的相互循环引用的问题

3、可达性分析法:GCRoots向下搜索,当一个对象到GC Roots没有任何引用链相连时,证明对象不可达。

①那些对象可以作为GCROOts?从永久代到年轻代的引用:

    虚拟机栈中引用的对象

    方法区中类静态变量属性引用的对象

    方法区中常用的对象

    本地方法栈中JNI引用的对象

    从永久代到年轻代的引用

②枚举根节点:过程中会出现短暂的停顿,设置一组oopMap的数据结构记录偏移量上什么类型的数据。                                                   安全点:特定位置暂停执行分为抢先式中断和主动式中断;安全区域:对不在执行的类或者对象进行枚举

8)什么时候进行垃圾收集?

①触发Minor GC条件(年轻代包括Eden和Survivor区域的内存回收):Eden区满

②触发Full GC条件:System.gc()、老年代空间不足、永久代空间不足、GC担保失败

③Major GC(老年代的清理)

9)怎么进行垃圾收集?(垃圾收集算法)

标记-清除:效率不高,占用空间,内存碎片过多
            复制算法:代价大:将内存缩小到原来的一半
            标记-整理:标记后让所有存活的对象向一端移动,然后直接清理掉边界以外的区域
            分代收集: 新生代:大批对象死去,使用复制算法;老生代:对象存活率高,没有额外空间进行分配担保,就使用标记                                   清除和标记整理来进行回收
            10)垃圾收集器

Serial收集器、parNew收集器、parallel收集器、CMS收集器

四、类加载机制

1)虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验转换解析和初始化,最终形成可被虚拟机直接使用的Java类型
    类加载的时机
        遇到new,getstatic,putstatic和invokestatic这四个字节码指令时
        使用reflect包的方法对类进行反射调用的时候
        当初始化一个类的时候,如果发现其父类还没有进行初始化
        虚拟机启动时,用户需要指定一个执行的主类

2)类加载过程:

加载:
    通过一个类的全限定名来获取定义此类的二进制字节流
    将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    在内存中生成一个代表这个类的class对象,作为方法区这个类的各种数据的访问入口
验证阶段:
    文件格式验证
    元数据验证
    字节码验证
    符号引用验证
准备阶段:正式为类变量分配内存并设置类变量初始值
解析阶段: 虚拟机将常量池内的符号引用替换成直接引用的过程
初始化阶段:  Java程序主导

3)双亲委派模型


    自上而下为启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器
        如果一个类加载器收到了类加载的请求,它首先不会自己尝试加载这个类,而是把这个请求委派给父类加载器完成,最终请求委派给顶层启动类加载器,父类无法完成加载,子类加载器才会尝试加载

4)应用实例

Tomcat
    部署在同一个服务器上的两个web应用程序所使用的Java类库实现相互隔离
    部署在同一个服务器上的两个web应用程序所使用的Java类库可以共享
    服务器需要尽可能保证自身不受部署的web应用程序影响
    支持jsp应用的web服务器,大多数都需要支持hotswap功能
OSGI
    灵活的类加载器架构,基于Java语言的动态模块化规范
    Bundle之间的依赖关系从传统的上层模块依赖转化为平级模块之间的依赖,类库可见性精确的控制; export过的package才能被外界访问
    可能实现热插拔功能,可以停用,重新安装某些模块,不影响整体
    可能出现死锁,互相引用导致的死锁,额外的复杂度,内存泄漏;解决办法:可以启用参数来单线程串行化的方式强制进行类加载动作
    

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值