JVM虚拟机

JDK、JRE、JVM的区别:

JVM:java visual machine,java虚拟机,整个java实现跨平台的核心,运行class文件

JRE:java runtime environment 包含JVM,以及一些核心类库

JDK:java development kit,JRE+一些工具包

 JVM的组成以及作用

 类加载系统:加载------》链接(验证、准备、解析)-----》初始化,将编译后的.class文件加载到JVM系统。

方法区:线程共享的,也是GC的区域。存放类加载后的版本信息、运行时常量池、域信息、接口信息、方法信息。注意:1.8以后的静态变量、字符串常量池已经放在了堆。方法区的实现1.8之前是永久代,1.8以后叫元空间,从堆内存迁移到了本地内存。

堆:线程共享的,也是GC的区域。存放对象以及数组、字符串常量池、静态变量。

虚拟机栈:线程私有的,不存在GC,包含局部变量表、操作数栈、方法出口、动态链接,每执行一个方法会压入一个栈帧,方法执行完会弹栈。

本地方法栈:线程私有的,不存在GC,虚拟机栈执行的是java方法,而本地方法栈执行的是native方法(C语言)

程序计数器:线程私有的,不存在GC,也没有OOM发生,记录的是下一条指令的执行地址。

执行引擎:包含解释器、JIT编译器、GC,负责执行字节码指令以及垃圾回收。

类加载子系统:

类加载器:用户自定义加载器 User ClassLoader----》程序/系统加载器----Application/System ClassLoader (加载类路径文件)》扩展类加载器 extentionClassLoader-----(加载jir/lib/ext包下的文件)》根加载器 (加载jre/lib/rt.jar)BoostrapClassLoader

加载过程:

  1. 加载:javac 命令后的会得出.class文件,将.class二进制文件加载到jvm内存。
  2. 连接: 验证:验证文件的安全性,例如是否是cafe baby魔数开头 class的版本是否被使用的jvm兼容。准备:给类中的静态变量赋初始值,分配空间。 解析:将常量池中的符号引用转为直接引用。
  3. 初始化:如果有静态变量,则执行clinit方法,给静态变量显式赋值。

 双亲委派:

是什么?:加载类时,自己不会去加载,而是交由自己的上一级加载器去加载。如:我们写的程序一般是通过程序加载器去加载的,而程序加载器不会先去加载,而去找他的上一级扩展类加载器加载,扩展类加载器也不会加载,而找到最顶层的根加载器。根加载器尝试加载,如果能加载直接返回,加载不了又会传给下一级。

作用:1、确定类只能被加载一次 2、保护了核心类库的安全性

实现类加载器:继承ClassLoader类,重写其findClass()/loadClass()(官方建议)

类的缓存机制:

   修改class文件后必须重启JVM。加载后的class文件会存放在缓存区,jvm每次读的时候会优先读取缓存区的数据,而变更后的文件要想见效,必须重新加载进缓存区。

JVM判断两个对象相等的条件:1、全类名相同 2、同一类加载器、

JVM的运行时包:由同一类加载器加载的相同包下的类组成了运行时包。只有属于同一运行时包的类才可互相访问(默认访问级别)

类的初始化顺序:   

  1.  父类的静态变量、静态代码块(静态变量与静态代码块按顺序)
  2. 子类的静态变量、静态代码块(静态变量与静态代码块按顺序)
  3. 父类的成员变量
  4. 父类的构造方法
  5. 子类的成员变量
  6. 子类的构造方法

 类的主动使用:

  1. new 关键字实例化
  2. 读取一个类的静态字段
  3. 调用类的静态方法
  4. 采用反射对类型进行反射调用
  5. 类初始化时,触发父类初始化
  6. main方法启动,触发
  7. jdk8新加入的默认方法,如果这个类接口的实现类初始化,那么该接口页必须初始化

类的被动使用:

除了以上主动使用,都是被动使用。

例如:

  1.  子类引用父类的静态变量,不会导致子类初始化
  2. 通过数组定义来引用类,不会触发此类初始化。
  3. 引用常量,常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的初始化

 

 

 

 栈

什么情况会产生栈溢出?

1、线程请求的栈深度大于JVM的栈深度

2、栈支持动态扩展,动态扩展时,无法申请足够的内存。

栈和堆的区别?

1、栈的物理地址是连续的,堆的物理地址是不连续的

2、栈是运行时单位,局部变量表存储的是基本数据类型的指,引用数据类型的引用,操作数栈、方法出口

3、栈是线程私有的,栈溢出抛出的异常是stackOverFlow,堆是线程共享的,堆抛出的异常是heap outOfMemory

4、栈的空间大小远远小于堆

 新生代:空间默认占1/3堆空间,分伊甸园区Eden、幸存者0区Survior 0(From)、幸存者1区Survior 1(To),新生代的垃圾收集叫Minor GC。

老年代:存放生命周期比较长的对象

创建对象的几种方式:

  1. new创建实例
  2. 反射Class.newInstance/Constructor.new Instance()
  3. 反序列化
  4. clone()   注意:此方式没有调用构造方法

 创建对象的流程:

  1. 检查类是否被加载,没有则加载
  2. 为对象分配内存,内存规整,用指针碰撞,否则用空闲列表
  3. 并发处理,默认采用TLAB,对象太大,采用CAS+重试
  4. 初始化内存空间(赋默认值)
  5. 设置对象头信息(类的元数据、hashCode、GC信息、锁信息)
  6. 显式初始化/代码块中初始化----->执行构造器方法

对象的内存布局

  1. 对象头 包含类型指针(指向方法区的类元信息)和运行时元数据(hashcode、分代年龄、锁状态等)
  2. 实例数据 (父类的实例数据、自身的实例数据)
  3. 对齐填充 主要为了对齐

 对象访问的模式

句柄池:栈引用指向句柄池,句柄池保存实例数据指针、类型指针。实例数据指针指向实例数据,类型指针,指向方法区的类数据。优点:对象移动,无需改变栈指针。

直接指针:栈引用指向实例数据,实例数据里面保存类型指针,类型指针指向方法区的类元数据。

优点:开销更小,定位更快

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值