[Java] 开课吧--JVM
双亲委派
- 向上委托,向下加载
- 收到加载任务后,先交给父类加载器,只有当父类加载器无法完成,才会执行加载
- 保证只有一个类加载器加载,避免重复加载
- 破坏:JDK 1.2后才使用,JDK 1.1的核心类没有通过双亲委派定义
如何判断两个Class对象是否相同
- class字节码相同
- classLoader相同
JVM运行数据区按线程使用情况分类
- 线程独享区域
- 虚拟机栈、本地方法栈、程序计数器
- 不需要垃圾回收
- 线程共享区域
- 堆和方法区
- 垃圾回收、类的静态数据和对象
HotSpot
- JDK 1.6:字符串常量池在永久代
- JDK 1.7:依然有永久代,但字符串常量池在堆中
- JDK 1.8:不存在永久代
字符串常量池
- 节省内存空间,所有类共享一个字符串常量池
- 如何存数据
- 对象存储
- 快速搜索:StringTable(hashtable)
- StringTableSize:决定搜索效率
堆
- JVM中最大的一块内存
- GC最重要区域
- 堆的内存分配通过垃圾收集器实现
- JVM启动时实现
- 存什么
- JDK 1.6:对象、数组
- JDK 1.7+:对象、数组、字符串常量池、静态变量
- 参数
- -Xms:初始大小,单位m,g
- -Xmx:最大大小
- -XMn:新生代(年轻代)
- -XX:SurvivorRatio=8:年轻代中Eden与Servivor比例,默认为8:1
- -XX:PermSize:非堆内存初始大小,一般默认200m
- -XX:MaxPermSize:菲堆最大大小
- -XX:NewSize(-Xns):年轻代内存初始大小
- -XX:MaxNewSize(-Xmn):年轻代最大大小
- 分配原则
- 优先在Eden分配,如果Eden不足,进行一次MinorGC
- 大对象直接进入老年代(超过Eden一半)
- 长期存活对象进入老年代(15次GC未被回收)
- 年轻代没有空间存放的对象进入老年代
- 分配方式
- 指针碰撞:内存地址连续(年轻代)
- 空闲列表:内存地址不连续(老年代)
- 分配安全
- 虚拟机给A线程分配内存过程中,指针未修改,B线程可能同时使用了同一块内存
- CAS(乐观锁):不加锁,假设没有冲突,如果冲突就重试,直到成功
- TLAB(本地线程分配缓冲):每个线程预先分配一块内存
- 分配担保
- 当在新生代中无法分配内存时,把新生代对象转移到老年代,然后把新对象放入腾空的新生代
- 对象内存布局
- 对象头:锁信息、对象年龄、类型指针
- 实例数据:成员变量
- 对齐填充
程序计数器
- 当前线程执行下一个字节码的行号
- 用于线程切换后,能恢复到正确执行的位置
Java虚拟机栈
- 基于栈和基于寄存器
- 基于栈(操作数栈):一个程序调用需要10个基于栈的指令,JVM一次编译,到处运行
- 基于寄存器:同样的一个程序调用只需要两三个基于寄存器的调用,和操作系统有关
- 栈帧
- 支持虚拟机进行方法执行的数据结构
- 存储方法的局部变量表、操作数栈、动态链接、方法返回地址
- 局部变量表--冰箱;操作栈--盘子
- 方法调用时创建
- 操作数栈的每个元素可以是任意Java数据类型,32位数据类型占一个栈容量
- 每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,可在类加载阶段或第一次使用时转换为直接引用(静态解析),或每次运行时转换为直接引用(动态连接)
- 静态解析:直接引用,即对应方法的内存地址
- 动态链接:class文件中,一个方法调用其他方法,需要将方法的符号引用转化为内存地址的直接引用。类中调用父类方法,运行时执行子类方法(多态)
- 方法返回:把当前栈帧出栈。正常完成出口 / 异常完成出口
本地方法栈
- 直接操作硬件,C++方法
方法执行
- 先由Java编译器编译为Java字节码,再由Java解释器逐条解释,或对热点代码由JIT编译器编译运行
- 热点代码:被多次调用的方法;被多次执行的循环体
- 方法调用计数器:先检查是否存在已编译版本,否则方法调用次数加1,超过阈值则启动编译
- 加载存储指令
- 将一个局部变量表加载到操作数栈:load系列
- 将一个数值从操作数栈加载到局部变量表:store系列
- 将一个常量加载到操作数栈:const系列、push系列、ldc系列
- JIT运行方式
- Server模式,Client模式
- 优化
- 公共子表达式消除
- 方法内联
- 逃逸分析(存在逃逸则无法优化)
- 栈上内存分配
- 标量替换
- 同步锁消除
方法调用
- 常见方法调用类型
- 私有方法:与类绑定,编译时确定
- 构造方法:与类绑定,编译时确定
- 静态方法:与类绑定,编译时确定
- 成员方法:不与类绑定,运行时确定
- 接口方法:不与类绑定,运行时确定
- 编译看左边,运行看右边
- 重载与重写
- 重写(overwrite):也叫方法覆盖,继承或实现关系下,子类和父类方法描述符(参数和返回值)一致,方法名称一致
- 重载(overloading):在同一个类中,方法名称一致,方法参数(类型和顺序)不一致,不关心返回值
- 可理解为运行时重新加载,即编译时按左边类,运行时才加载右边真正类型
- 静态绑定和动态绑定
- 通过类名、方法名、方法描述符识别方法
- 属性看左,方法看右
- 通过父类引用访问子类的属性,需要强制转型
- 方法调用指令
- invokevirtual:调用非静态非私有方法(多态)
- invokeinterface:调用接口方法(多态)
- invokespecial:调用非静态私有方法、构造方法
- invokestatic:调用静态方法
- invokedynamic
- 方法调用过程
- 静态绑定方法:直接在运行时常量池找到引用
- 动态绑定方法:根据父类方法表确定要查找的方法索引(编译看左),从子类方法表中开始,找不到再去父方法表找
- 虚分配
- Father father = new Son();
- father指针指向son对象
- 根据本地变量表,找调用该虚方法的对象
- 取出对象头中的类型指针,找到Class对象
- 找到Class对象后,找到对应的虚方法表
- 找到对应的方法,进行方法调用
- 如果找不到,则去父类对象查找,最终找不到则报错
public class DynamicCall01 {
public static void main(String[] args) {
Father father = new Son();
// 多态,发生方法重载
father.f1();
// 打印结果: Son-f1()
char c = 'a';
father.f1(c);
// 打印结果: father-f1() para-int 97
}
} // 被调用的父类
class Father {
public void f1() {
System.out.println("father-f1()");
} public void f1(int i) {
System.out.println("father-f1() para-int " + i);
}
} // 被调用的子类
class Son extends Father {
public void f1() {
// 覆盖父类的方法
System.out.println("Son-f1()");
}
public void f1(char c) {
System.out.println("Son-s1() para-char " + c);
}
}
- 例题
- 对于father.f1(),子类父类都有,在各自方法表中是独立的两项(编号相同),编译期间无法确定,故在运行时根据创建的对象,发生重载
- 对于father.f1(c),f(char)父类没有,编译时将char自动转型为int,而f(int)只有父类有,子类直接继承,也不会写在子类方法表中,故不会发生重载。如果Son中也有f1(int i),则会发生重载
- 子类对象通过父类引用调用的方法,必须在父类中出现过,否则编译无法通过
- 例题
- 内联缓存
- 加快动态绑定的优化技术
垃圾回收
- 标记阶段
- 引用计数:实现简单,无法处理循环引用问题。Python采用
- 可达性分析:枚举GC Roots-->STW-->追踪标记。Java采用
- 回收过程
- 第一次判断:使用可达性分析后,判断对象不可达
- 第二次判断:finalize(),重新建立可达性关联,否则会被第二次标记
- 垃圾清除阶段
- 标记-清除算法:效率不高,GC时需停止程序,清理后内存不连续
- 复制算法:没有标记和清除过程,效率高,空间连续,需要两倍空间(空间换时间),适用于新生代(存活对象少,垃圾对象多)
- 标记-压缩算法:适用于老年代(存活对象多)
- 垃圾回收器
- 按执行方式分类
- 串行回收器:Serial、Serial Old
- 并行回收器:ParNew、Parallel Scavenge、Parallel Old
- 并发回收器:CMS、G1
- 按垃圾分代关系
- 新生代收集器:Serial、ParNew、Parallel Scavenge
- 老年代收集器:Serial Old、Parallel Old、CMS
- 整堆收集器:G1
- 性能指标
- 吞吐量:运行用户代码时间/(运行用户代码时间+垃圾收集时间)【高吞吐,后台】
- 暂停时间:应用程序线程暂停,GC线程执行的时间段【低延迟,页面】
- CMS
- 低延迟
- 标记-清除算法
- 不能和PS配合
- 初始标记->并发标记->重新标记->并发清除
- 按执行方式分类
[Java] 开课吧--JVM的更多相关文章
- (转)Java 详解 JVM 工作原理和流程
作为一名Java使用者,掌握JVM的体系结构也是必须的.说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java编程语言.Java类文件格式.Java虚 ...
- 关于编写Java程序让Jvm崩溃
今天在书上看到一个作者提出一个问题“怎样通过编写Java代码让Jvm崩溃”,我看了之后也不懂.带着问题查了一下,百度知道里面有这样一个答案: package jvm; public class Cra ...
- Java 7 jstat – JVM Statistics Monitoring Tool【翻译】
原文地址:Java 7 jstat 本文内容 语法 参数 描述 虚拟机标识符 选项 一般选项 输出选项 示例 先发出来,然后慢慢翻译~ 语法 jstat [ generalOption | outpu ...
- java源代码分析----jvm.dll装载过程
简述众所周知java.exe是java class文件的执行程序,但实际上java.exe程序只是一个执行的外壳,它会装载jvm.dll(windows下,以下皆以windows平台为例,linux下 ...
- Java虚拟机(JVM)中的内存设置详解
在一些规模稍大的应用中,Java虚拟机(JVM)的内存设置尤为重要,想在项目中取得好的效率,GC(垃圾回收)的设置是第一步. PermGen space:全称是Permanent Generation ...
- 写Java程序让Jvm崩溃
package jvm; public class HeapCrash { public static void main(String[] args) { //Object[] o = {“abc” ...
- [Java] Java 技术和 JVM 基础
Java 由 Sun 公司在 1995 首次发布,既是一门编程语言,也是一个计算平台. Java 运行时版本 Java Runtime Edition 当你下载 Java 完时候,你会得到一个 Jav ...
- Java对象在JVM中的生命周期
当你通过new语句创建一个java对象时,JVM就会为这个对象分配一块内存空间,只要这个对象被引用变量引用了,那么这个对象就会一直驻留在内存中,否则,它就会结束生命周期,JVM会在合适的时 ...
- java虚拟机学习-JVM调优总结-分代垃圾回收详述(9)
为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对象, ...
随机推荐
- JAVA题目:正整数n若是其平方数的尾部,则称n为同构数 如:5*5=25, 25*25=625 问: 求1~99中的所有同构数
1 /*题目:正整数n若是其平方数的尾部,则称n为同构数 2 如:5*5=25, 25*25=625 3 问: 求1~99中的所有同构数 4 */ 5 //分析:将1-99分为1-9和10-99,用取 ...
- Android Studio 如何在TextView中设置图标并按需调整图标大小
•任务 相信大家对这张图片都不陌生,没错,就是 QQ动态 向我们展示的界面. 如何实现呢? •添加文字并放入图标 新建一个 Activity,取名为 QQ,Android Studio 自动为我们生成 ...
- 全网最详细的Linux命令系列-iptrad-ng网络流量监测命令
观察网络流量的工具:IPTRAF 想知道你的Linux系统上网络流量有多大吗?想知道是哪一块网卡承载着网络流量吗?想知道哪一个进程产生了网络流量吗?iptraf可以帮你做到.在最新的Linux rel ...
- 再学dockerfile
前言 docker的系统学习可以看我这篇博文:https://www.cnblogs.com/zisefeizhu/p/11298818.html 有非常详细的讲解 容器现在都是用kubernetes ...
- [矩阵乘法]斐波那契数列IV
[ 矩 阵 乘 法 ] 裴 波 拉 契 数 列 I V [矩阵乘法]裴波拉契数列IV [矩阵乘法]裴波拉契数列IV Description 求数列f[n]=f[n-2]+f[n-1]+n+1的第N项, ...
- Vue.js 带下拉选项的输入框(Textbox with Dropdown)组件
带下拉选项的输入框 (Textbox with Dropdown) 是既允许用户从下拉列表中选择输入又允许用户自由键入输入值.这算是比较常见的一种 UI 元素,可以为用户提供候选项节省操作时间,也可以 ...
- BUAA_OO_第三单元
一.JML初探 JML(Java Modeling Language)作为一种形式化语言,可以约束Java代码中类和方法的状态和行为形成规格,通过将一系列具体代码实现抽象成明确的行为接口,可以形成 ...
- Mybatis3源码笔记(三)Configuration
1. XMLConfigBuilder 上一篇大致介绍了SqlSession的生成.在DefaultSqlSessionFactory的构造函数中就提到了Configuration这个对象.现在我们来 ...
- Day14_77_反射( newInstance() 方法)
newInstance() 方法 * 通过反射获取class类型的对象之后,可以通过该对象创建所对应的class类型的对象 * newInstance() 用来创建Class获取的类所表示的一个新实例 ...
- 1016 Phone Bills
A long-distance telephone company charges its customers by the following rules: Making a long-distan ...