JVM核心技术(第一篇)
Java基础知识
java是一个面向对象的,静态类型,编译执行,有VM/GC和运行时的跨平台的高级语言。
一. 字节码技术
将写好的java文件编译成class
javac .\TestJvm.java
查看字节码
javap -c TestJVM
查看更详细的字节码
javap -c -verbose TestJVM
字节码的运行时结构
JVM是一个基于栈的计算机器。每个线程都有他所对应的线程栈,用于存储栈帧。每一次方法调用,都会创建一个栈帧。
栈帧由操作数栈,局部变量数组以及一个Class引用(也叫动态链接)组成。
操作数栈:每个帧都包含了一个后入先出的栈,称为操作数栈。
局部变量表:用于存放方法参数和内部定义的局部变量。局部变量表的容量以变量槽(Slot)为单位,一个Slot只能存放一个boolean、byte、char、shoert、int、float、reference或returnAddress类型的数据
Class引用:指向当前方法在运行时常量池中对应的class
二、JVM类加载器
类的生命周期
- 加载:找class文件
- 校验 :验证格式,依赖
- 准备 :静态字段,方法表
- 解析:符号解析为引用
- 初始化 :构造器,静态变量赋值,静态代码块
- 使用
- 卸载
类的加载时机
- 当虚拟机启动时,初始化用户指定的主类,就是启动执行的 main 方法所在的类;
- 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类,就是 new
一个类的时候要初始化; - 当遇到调用静态方法的指令时,初始化该静态方法所在的类;
- 当遇到访问静态字段的指令时,初始化该静态字段所在的类
- 子类的初始化会触发父类的初始化
- 如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,
会触发该接口的初始化 - 使用反射 API 对某个类进行反射调用时,初始化这个类,其实跟前面一样,反射调用
要么是已经有实例了,要么是静态方法,都需要初始化 - 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的
类
不会初始化(可能会加载)
- 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化
- 定义对象数组,不会触发该类的初始化
- 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类
- 通过类名获取 Class 对象,不会触发类的初始化,Hello.class 不会让 Hello 类初始化。
- 通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触
发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。Class.forName
(“jvm.Hello”)默认会加载 Hello 类。 - 通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作(加载了,但是
不初始化)
三类类加载器
从上到下依次是:
- 启动类加载器(BootstrapClassLoader)
- 扩展类加载器(ExtClassLoader)
- 应用类加载器(AppClassLoader)
类加载器特点:
双亲委派、负责依赖、缓存加载
加载过程:如一个Hello.class文件,不考虑自定义加载器,首先会在AppClassLoader中检查是否已经加载过,如果加载过就不加载了。如果没有加载过,就会拿到父加载器,那么父加载器(ExtClassLoader)就会检查是否加载过,如果没有,就再往上,让BootStrapClassLoader检查是否加载过。
如果还是没有,因为他的上面已经没有父加载器了,那么他就开始自己加载,如果能加载,他就自己加载。不能加载,就下沉到子加载器去加载,一直到最底层,如果没有类加载器能加载就抛出异常ClassNotFoundException
添加引用类的几种方式
- 放到JDK的lib/ext下,或者-Djava.ext.dirs
- java -cp/classpath 或者将class文件放在当前路径
- 自定义ClassLoader加载
- 拿到当前执行类的ClassLoader,反射调用addUrl方法添加jar或路径
public class Test1 {
public static void main(String[] args) throws MalformedURLException, NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
String appurl="file:/d:/logs/";
URLClassLoader classLoader = (URLClassLoader)Test1.class.getClassLoader();
Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addURL.setAccessible(true);
URL url=new URL(appurl);
addURL.invoke(classLoader,url);
Class.forName("Test2");
}
}
我将Test2.class文件放在d盘的logs文件夹下。
三、JVM内存结构
Jvm整体结构:
可以看到,我们的JVM进程里面除了堆还有栈、非堆、JVM自身。而我们的操作系统里还有其他进程。
所以我们设置堆内存的时候,不能设置为机器的内存大小,如4G的机器千万不能把-Xms -Xmx 设置为4G,一般设置为机器内存的60%-70%。
JVM栈结构:
栈:线程栈,也叫Java方法栈,每启动一个线程就会创建一个栈,如果使用了JNI方法,就会分配一个单独的本地方法栈。线程执行过程中,一般会有多个方法组成调用关系,如方法A调用方法B,每执行到一个方法,就会创建一个栈帧。
所有的原生对象类型(如int,long)和对象引用地址都在栈上存储。
JVM堆结构:
堆:对象、对象成员以及类定义、静态变量都在堆上。
什么是JMM?
Java内存模型。明确定义了不同的线程之间,通过哪些方式,在什么时候可以看到其他线程保存在共享变量中的值;以及如何对共享变量进行同步。JMM规范的是线程间的交互操作。
从抽象上来看,JMM定义了线程和主内存之间的抽象关系。
四、JVM启动参数
JVM启动参数有如下几类:
以-开头为标准参数,所有的 JVM 都要实现这些参数,并且向后兼容。如:++-server++
以-D开头的,设置系统属性 如:++-Dfile.encoding=UTF-8++
以 -X 开头为非标准参数, 基本都是传给 JVM 的,
默认 JVM 实现这些参数的功能,但是并不保证所
有 JVM 实现都满足,且不保证向后兼容。 可以使
用 java -X 命令来查看当前 JVM 支持的非标准参 如:++-Xmx8g++
数。以 –XX:开头为非稳定参数, 专门用于控制 JVM
的行为,跟具体的 JVM 实现有关,随时可能会在
下个版本取消。-XX:+-Flags 形式, +- 是对布尔值进行开关 如:++-XX:+UseG1GC++
-XX:key=value 形式, 指定某个选项的值 如:++-XX:MaxPermSize=256m++
4.1 系统属性参数
-Dfile.encoding=UTF-8 -Duser.timezone=GMT+08
或者通过
System.setProperty("a","A100");设定,Linux上还可以通过a=A100 java XXX 设定。
4.2 运行模式
- -server:设置 JVM 使用 server 模式,特点是启动速度比较慢,但运行时性能和内存管理效率
很高,适用于生产环境。在具有 64 位能力的 JDK 环境下将默认启用该模式,而忽略 -client 参
数。 - -client :JDK1.7 之前在32位的 x86 机器上的默认值是 -client 选项。设置 JVM 使用 client 模
式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或
者 PC 应用开发和调试。此外,我们知道 JVM 加载字节码后,可以解释执行,也可以编译成本
地代码再执行,所以可以配置 JVM 对字节码的处理模式: - -Xint:在解释模式(interpreted mode)下运行,-Xint 标记会强制 JVM 解释执行所有的字节
码,这当然会降低运行速度,通常低10倍或更多。 - -Xcomp:-Xcomp 参数与-Xint 正好相反,JVM 在第一次使用时会把所有的字节码编译成本地
代码,从而带来最大程度的优化。【注意预热】 - -Xmixed:-Xmixed 是混合模式,将解释模式和编译模式进行混合使用,有 JVM 自己决定,这
是 JVM 的默认模式,也是推荐模式。 我们使用 java -version 可以看到 mixed mode 等信息。
4.3 堆内存
-Xmx, 指定最大堆内存。 如 -Xmx4g. 这只是限制了 Heap 部分的最大值为4g。
这个内存不包括栈内存,也不包括堆外使用的内存。
-Xms, 指定堆内存空间的初始大小。 如 -Xms4g。 而且指定的内存大小,并
不是操作系统实际分配的初始值,而是GC先规划好,用到才分配。 专用服务器上需要保持 –Xms 和 –Xmx 一致,否则应用刚启动可能就有好几个 FullGC。
当两者配置不一致时,堆内存扩容可能会导致性能抖动。
-Xmn, 等价于 -XX:NewSize,使用 G1 垃圾收集器 不应该设置该选项,在其他的某些业务场景下可以设置。官方建议设置为 -Xmx 的 1/2 ~ 1/4.
-XX:MaxPermSize=size, 这是 JDK1.7 之前使用的。Java8 默认允许的Meta空间无限大,此参数无效。
-XX:MaxMetaspaceSize=size, Java8 默认不限制 Meta 空间, 一般不允许设置该选项。
-XX:MaxDirectMemorySize=size,系统可以使用的最大堆外内存,这个参数跟 -Dsun.nio.MaxDirectMemorySize 效果相同。
-Xss, 设置每个线程栈的字节数。 例如 -Xss1m指定线程栈为1MB,与-XX:ThreadStackSize=1m 等价
4.4 GC相关
-XX:+UseG1GC:使用 G1 垃圾回收器
-XX:+UseConcMarkSweepGC:使用 CMS 垃圾回收器
-XX:+UseSerialGC:使用串行垃圾回收器
-XX:+UseParallelGC:使用并行垃圾回收器
// Java 11+
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
// Java 12+
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
4.5 分析诊断
-XX:+-HeapDumpOnOutOfMemoryError 选项, 当 OutOfMemoryError 产生,即内存溢出(堆内存或持久代)时自动 Dump 堆内存。
示例用法: java -XX:+HeapDumpOnOutOfMemoryError -Xmx256m ConsumeHeap
-XX:HeapDumpPath 选项, 与 HeapDumpOnOutOfMemoryError 搭配使用, 指定内存溢出时 Dump 文件的目录。
如果没有指定则默认为启动 Java 程序的工作目录。
示例用法: java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/ ConsumeHeap
自动 Dump 的 hprof 文件会存储到 /usr/local/ 目录下。
-XX:OnError 选项, 发生致命错误时(fatal error)执行的脚本。
例如, 写一个脚本来记录出错时间, 执行一些命令, 或者 curl 一下某个在线报警的 url.
示例用法:java -XX:OnError="gdb - %p" MyApp
可以发现有一个 %p 的格式化字符串,表示进程 PID。
-XX:OnOutOfMemoryError 选项, 抛出 OutOfMemoryError 错误时执行的脚本。
-XX:ErrorFile=filename 选项, 致命错误的日志文件名,绝对路径或者相对路径。
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1506,远程调试
4.6 JavaAgent
Agent 是 JVM 中的一项黑科技, 可以通过无侵入方式来做很多事情,比如注入 AOP 代码,执行统
计等等,权限非常大。这里简单介绍一下配置选项,详细功能需要专门来讲。
设置 agent 的语法如下:
-agentlib:libname[=options] 启用 native 方式的 agent, 参考 LD_LIBRARY_PATH 路径。
-agentpath:pathname[=options] 启用 native 方式的 agent。
-javaagent:jarpath[=options] 启用外部的 agent 库, 比如 pinpoint.jar 等等。
-Xnoagent 则是禁用所有 agent。
以下示例开启CPU使用时间抽样分析:JAVA_OPTS="-agentlib:hprof=cpu=samples,file=cpu.samples.log
JVM核心技术(第一篇)的更多相关文章
- JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇
JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇 作为一个使用Java语言开发的程序员,我们都知道,要想运行Java程序至少需要安装JRE(安装JDK也没问题).我们也知道我们Java程序 ...
- 深入jvm虚拟机--第一篇 void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState tos_out) 函数
今天第一次使用虚拟姐打断点,断点设置在了void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState t ...
- java核心技术第一篇之数据库基础
01.数据库的概念: 1).数据库的概念:数据库(Database),就是存储数据的仓库. 2).作用:用来存储和管理大量数据的.内部采用了非常便于查询的机制来存储数据,能保证我们在大量数据的情况下 ...
- Eclipse插件开发 学习笔记 PDF 第一篇到第四篇 免分下载 开发基础 核心技术 高级进阶 综合实例
<<Eclipse插件开发 学习笔记>>,本书由浅入深.有重点.有针对性地介绍了Eclipse插件开发技术,全书分为4篇共24章.第一篇介绍Eclipse平台界面开发的基础知识 ...
- JVM学习篇-第一篇
JVM学习篇-第一篇 JDK( Java Development Kit): Java程序设计语言.Java虚拟机.Java类库三部分统称为JDK,JDK是用于支持Java程序开发的最小环境** ...
- [转载] Android Metro风格的Launcher开发系列第一篇
前言:从毕业到现在已经三年多了,回忆一下这三年基本上没有写过博客,总是觉得忙,没时间写,也觉得写博客没什么大用.但是看到很多大牛们都在写博客,分享自己的东西,所以嘛本着向大牛看齐,分享第一,记录第二的 ...
- Android Metro风格的Launcher开发系列第一篇
前言:从毕业到现在已经三年多了,回忆一下这三年基本上没有写过博客,总是觉得忙,没时间写,也觉得写博客没什么大用.但是看到很多大牛们都在写博客,分享自己的东西,所以嘛本着向大牛看齐,分享第一,记录第二的 ...
- 第一篇 入门必备 (Android学习笔记)
第一篇 入门必备 第1章 初识Android 第2章 搭建你的开发环境 第3章 创建第一个程序--HelloWorld 第4章 使用Android工具 ●Android之父 Android安迪·罗 ...
- Java Nested Classes(内部类~第一篇英文技术文档翻译)
鄙人最近尝试着翻译了自己的第一篇英文技术文档.Java Nested Classes Reference From Oracle Documentation 目录 嵌套类-Nested Classes ...
- spring boot实战(第一篇)第一个案例
版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] spring boot实战(第一篇)第一个案例 前言 写在前面的话 一直想将spring boot相关内容写成一个系列的 ...
随机推荐
- SpringBoot入门学习看这一篇就够了
1.SpringBoot是什么? SpringBoot是一套基于Spring框架的微服务框架. 2.为什么需要SpringBoot 由于Spring是一个轻量级的企业开发框架,主要的功能就是用于整合和 ...
- Java中HashMap的源码分析
先来回顾一下Map类中常用实现类的区别: HashMap:底层实现是哈希表+链表,在JDK8中,当链表长度大于8时转换为红黑树,线程不安全,效率高,允许key或value为null HashTable ...
- DAOS 分布式异步对象存储|架构设计
分布式异步对象存储 (DAOS) 是一个开源的对象存储系统,专为大规模分布式非易失性内存 (NVM, Non-Volatile Memory) 设计,利用了SCM(Storage-Class Memo ...
- 20182217_刘洪宇 后门原理与实践 EXP2
1.后门概念 后门就是不经过正常认证流程而访问系统的通道. 哪里有后门呢? 编译器留后门 操作系统留后门 最常见的当然还是应用程序中留后门 还有就是潜伏于操作系统中或伪装为特定应用的专用后门程序. - ...
- javascript 取自己
var own=docment.currentScript;
- DFS 深搜专题 入门典例 -- 凌宸1642
DFS 深搜专题 入门典例 -- 凌宸1642 深度优先搜索 是一种 枚举所有完整路径以遍历所有情况的搜索方法 ,使用 递归 可以很好的实现 深度优先搜索. 1 最大价值 题目描述 有 n 件物品 ...
- Egress-Assess-出口数据安全功能测试
简介 Egress-Assess是一款用于测试出口数据检测功能的工具,该工具可辅助完成数据安全模型测试. 在各种情况下,我们的团队都会尝试从我们正在运行的网络中提取数据,并将其移至另一个位置以进行脱机 ...
- MySQL提升笔记(2):存储引擎盘点
在前面我们了解了server层调用存储引擎层接口来完成sql的执行,使用存储引擎的好处是:每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表. 需要注意的是,存储引擎是基于表的,而不是数 ...
- 安装maven工程报错"Failed to execute goal on project...Could not resolve dependencies for project..."
我在qingcheng_interface中Lifecycle目录下执行install命令后报错"Failed to execute goal on project...Could not ...
- jdbcTemplate事务管理
1.基于TransactionTemplate的编程式事务管理 Spring之路(39)–基于TransactionTemplate的编程式事务管理 本篇通过TransactionTemplate类, ...