目录
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