• 18.JVM


    目录

    1.编写源代码

    2.JDK (Java Development Kit)

    3.JRE(Java Runtime Environment)  Java运行时环境

    4.JVM

    1.类名

    2.类文件放在哪?

    13JVM按需加载类,那么何时加载一个类?

    4.类文件是怎么来的?

    5.类文件中的主要数据:

    6.为什么要进行类的加载?

    7.为什么类文件要按需加载,并且以类为单位加载?

    8.类在内存中只会存在一份

    9.类的加载过程

    10.类的初始化会执行我们的哪些代码,顺序是什么?

    11.类的数据被加载到内存的啥位置了?

    12.默认类的加载器有哪些:

    13.加载时,ClassLoader怎么知道一个类对应的类文件所在的位置?

    14.如果加载时一个类不存在,会出现异常

    5.类加载时常遇到的问题:双亲(parent)委派机制

    6.java中的数据类型:

    7.JVM的大体启动过程:控制权如何交到我们手中

    8.垃圾回收

    1.那么那些是GC的重点?

    2.那么如何判断哪些对象是垃圾对象(不会再被使用的对象)

    9.如何进行垃圾回收(内存空间的回收)


    学习JVM主要是学习java程序运行宁阶段是咋工作的,帮助我们更好地写程序。

    1.编写源代码

    源码数据一定要存储在某个介质上,并且希望是持久化的存储,所以一般般存在硬盘。

    抽象成文件形式(一般以*.java结尾,称为java源文件)

    程序 = 数据 +指令

     上述阶段,一般称为开发阶段。(需求分析、编码、编译、测试)

    下面进入运行时阶段(Runtime Phase)

    CPU无法直接和硬盘(IO设备)做直接的数据交换,我们应该怎么做?


    2.JDK (Java Development Kit)

    用于给Java开发人员使用的小工具箱

    里面放了:

    提前准备好的程序(*.exe / *>dll): 编译器、调试工具、运行时的分析工具

    官方提供的所有人都可以使用的类文件:*.class

    3.JRE(Java Runtime Environment)  Java运行时环境

    用于给一般用户运行别人写好的Java程序的一组环境

     这些类不够用,锁把一些官方指定了标准,但按照JDK(JRE)不会安装的类称为JavaEE(Enterprise Edition 企业版)

    打包时,只给普通用户使用,只打包*.class就够用了,不用打包EE的 *.class

    类文件中的数据:类的基本属性、常量池、方法(方法的信息+指令)

    ClassLoader要加载一个类,主要就是加载这些数据到内存中


    4.JVM

    1.类名

    1.权威类名:包名+类名称   mxj.demo.mxj

    JVM内部:内部加载器+权威类名,确定一个类是否存在

    2.默认情况下:  类加载器(ClassLoader)+权威类名

    2.类文件放在哪?

    硬盘中,以文件的形式出现最为常见

    13JVM按需加载类,那么何时加载一个类?

    实例化对象、访问静态属性、调用静态方法、子类用到父类

    什么叫用到?

    使用一个类,进行对象的实例化(构造对象时)

    使用一个类时,会触发这个类的父类(“父类”:类的继承、接口的实现、接口的继承)

    4.类文件是怎么来的?

    经过编译器,将java源文件编译出来

    5.类文件中的主要数据:

    基本信息(静态属性)、方法(方法信息、指令(字节码))、常量

    6.为什么要进行类的加载?

    按照冯诺依曼体系,CPU无法直接读取硬盘的数据,需要先加载到内存中

    7.为什么类文件要按需加载,并且以类为单位加载?

    相对来说,节省内存空间,实现方便

    8.类在内存中只会存在一份

    9.类的加载过程

    加载loading、链接Linking、初始化Initializing

    10.类的初始化会执行我们的哪些代码,顺序是什么?

    (1)属性的初始化赋值

    (2)静态构造代码块

    父类的初始化一定在子类之前完成

    按照书写顺序

    11.类的数据被加载到内存的啥位置了?

    逻辑上,房子啊方法区。但不同的JVM实现,可以有进一步讨论空间

    12.默认类的加载器有哪些:

    不同的类,由不同的类加载

    Boostrap ClassLoader(启动类加载器):加载SE下的标准类(java.lang.String、java.util.List、

    java.io.InputStream)

    Extenttion ClassLoader(扩展类加载器):加载SE下的扩展类(我们一般用不上)

    Application ClassLoader(应用类加载器):我们写的类、我们通过maven或者其他工具引入的第三方类

    13.加载时,ClassLoader怎么知道一个类对应的类文件所在的位置?

    启动、扩展类加载器根据固定位置找。

    应用类加载器,根据class path的路径依次查找

    14.如果加载时一个类不存在,会出现异常

    (ClassNotFound、NoClassF...)


    5.类加载时常遇到的问题:双亲(parent)委派机制

    默认的三个类加载器之间遵守的一个规范:

    1.三个类加载器之间存在

    2.ApplicationClassLoader需要类加载的时候,先委派给双亲去加载

    如果parent加载成功这个类了,就不用再加载了,否则就自己去加载

    3.目的是防止加载进来用户写好的恶意代码

    前提知识点:一个类(A)用到其他类(BCD),则其他的这些类(BCD)的加载动作,默认是由当时加载A类的加载器来加载

    面试重点:

    假设有一个com.mxj.demo.Main用到了java.lang.String类还是java.lang.String?

             

     com.mxj.demo.Main类被哪个类加载器加载?  ApplicationClassLoader去加载

    Main用到了java.lang.String  ,默认让  ApplicationClassLoader去加载

    如果有双亲委派,ApplicationClassLoader优先让BootStrapClassLoader去加载rt.jar下的。所以,不会加载我们自己写的。


    6.java中的数据类型:

    1.基本数据类型(Primitive Type):空间保存的是值,访问内存是一次性的

    2.引用数据类型(Reference Type):空间中保存的真实对象的线索(地址、其他信息)

                                                             访问内存至少两次

    一、Java中的基本类型:

    1.数值类型

           (1)整形 byte、char、int、long、

           (2)非整形  float、double

    2.布尔类型

    二、Java中的引用类型:

    类、接口、数组、注解


    执行引擎:就是对CPU的模拟,所以CPU的工作与执行引擎相同

    1.读取PC中保存的值(一般是地址)

    2.根据PC的值,去内存中(方法区),读取一条指令(字节码)

    3.执行具体的字节码

    4.默认情况下,PC的值自动加一(语句自动执行下一条)


    7.JVM的大体启动过程:控制权如何交到我们手中

    我们main方法的第一条语句(字节码)是如何被执行起来的

    java.exe -classpath指定类的加载路径   启动类名称

    java.exe  com.mxj.demo.Main   以这个类的main方法作为程序的启动入口

    1.[OS]收集要启动进程的信息,程序是C:/Program Files/Java/jdk/bin/java.exe,参数是com.mxj.demo.Main

    2.[OS]根据程序,启动进程,执行java.exe当时写的程序入口(C语言里的main函数)

    3.[JVM]读取参数,找OS申请必要的内存(malloc)、创建必要的执行应用类和类加载器

    4.[JVM]执行引擎,要求类加载器进行com.mxj.demo.Main类的加载

    5.[JVM]创建主线程,把PC的值设成com.mxj.demo.Main类下的static main的第一条指令的地址

    6.[JVM]开启执行引擎的指令执行循环,执行第一条语句

    7.[Java App]开始我们代码的执行

    8. .....直到所有前台线程

    9.[JVM]进行必要资源的回收

    10.[JVM]进程退出


    8.垃圾回收

    有了GC(垃圾回收)之后,让开发人员只需要考虑什么时候需要一块内存,而不需要考虑什么内存不再被需要了。

    逻辑上,把内存的使用权和所有权分离了,我们只享受一段内存的使用权,没有所有权。

    好处:不需要考虑内存的释放问题

    坏处:内存彻底和我们无缘

    1.那么那些是GC的重点?

    1.PC区域:一个PC和一个线程关联,只要线程活着,PC就一定需要

    分配时机:创建一个新线程

    回收时机:这个PC对应线程的最后一条指令执行结束之后

    分配和回收的时机非常简单,不需要GC做过多的参与

    2.栈区域:每个线程都有自己的栈,创建线程时为其分配栈空间。线程执行结束后回收栈空间

    栈上栈帧的分配:当执行一个方法的调用时

    回收栈帧:当该方法return时

    分配和回收的时机非常简单,不需要GC做过多的参与

    3.方法区(包含运行常量池)

    分配:类的加载

    回收:类的卸载

    不需要GC做过多的参与

    4.堆区(以对象为基本单位)

    分配:实例化一个对象     时机非常明确:new 语句出现的时候

    回收:该对象一定没有在被使用的时候

    一个对象没有被使用,但是还没被回收。        可以接受,一部分内存被浪费了。

    一个对象还在使用,但被回收了。                   不可接受,造成野指针(访问了错误的空间)


    2.那么如何判断哪些对象是垃圾对象(不会再被使用的对象)

    1.引用指针法

     object.ref_count 何时增加,何时减少,关键就看引用的生命周期。

    增加:每多一个引用指向该对象(进行了引用赋值),就要增加

    减少:引用出现的位置

    (1)栈帧中(局部变量),方法执行结束,引用声明周期消亡,ref_count--;

    (2)出现在类中(静态属性),类被卸载时,引用生命周期消亡

    (3)对象的死亡引起的连锁反应

              对象死亡,对象中的引用失效,导致该引用指向的对象的ref_Count--,可能引起其他对象继续死亡。

    (4)引用还在,但指向其他对象了

    9.如何进行垃圾回收(内存空间的回收)

    对象的生命:每经历一次GC,对象的年龄+1

    大部分情况下,只会进行新生带的GC。随着新生代GC的进行,会有越来越多的对象进入老年代。

    由于老年代的GC成本较大,所以一般会尽量减少老年代GC

    随着老年代GC对象越来越多,达到某个阈值,就会进行老年代GC

    大部分情况下,老年代GC总是由于某次新生代GC引起的。所以,新生带GC发生时,一般也代表了整个GC。

    如果对象本身很大,复制起来成本很高,一般直接进入老年代。

    为啥15岁成年:

    Hostpot内部实现对象时,用了4个bit来记录年龄,年龄就是0-15

  • 相关阅读:
    4核8g服务器能支持多少人访问?
    表达矩阵任意两个基因相关性分析 批量相关性分析 tcga geo 矩阵中相关性强的基因对 基因相关性
    分开的两个程序使用共同的mysql,一端更新了表,另一端怎么及时更新缓存,使用mybatis
    Linux从root账号切换到普通账号并执行shell脚本
    操作系统-进程与线程(同步互斥典型模型-生产者,消费者模型、吸烟者问题)
    ChromeDriver全版本下载教程
    695. 岛屿的最大面积
    将日志压缩并归档到 Amazon S3 Glacier 存储层中
    第五章. 可视化数据分析分析图表—概念介绍
    Linux内存不够了?看看如何开启虚拟内存增加内存使用量
  • 原文地址:https://blog.csdn.net/mmm174/article/details/128075032