JVM的学习一

学习JVM(一)

一、java字节码技术

1.什么是字节码

Java bytecode 由单字节(byte)的指令组成,理论上最多支持 256 个操作码(opcode)。 实际上 Java 只使用了200左右的操作码, 还有一些操作码则保留给调试操作。Java的字节码技术,就是java程序具有可移植性和适应所有操作系统的根本原因。因为不管是什么样的操作系统最后计算机解析的都是java的字节码,所以不会受到影响。
根据指令的性质,主要分为四个大类:

  1. 栈操作指令,包括与局部变量交互的指令 2. 程序流程控制指令
  2. 对象操作指令,包括方法调用指令
  3. 算术运算以及类型转换指令

2.生成字节码

在这里插入图片描述
编译:javac demo/jvm0104/HelloByteCode.java
查看字节码:javap -c demo.jvm0104.HelloByteCode

结果如下:

在这里插入图片描述

3.字节码的运行时结构

JVM 是一台基于栈的计算机器。 每个线程都有一个独属于自己的线程栈(JVM Stack),用于存储栈帧(Frame)。每一次方法调用,JVM 都会自动创建一个栈帧。 栈帧由操作数栈, 局部变量数组以及一个 Class 引用组成。 Class 引用 指向当前方法在运行时常量池中对应的 Class。

这是一个动态的例子,按照字节码顺序 常量1进入局部变量区0,常量2进入局部变量区1, 然后加载0,1进入栈进行相加操作 然后与常量5进行相乘,值进入局部变量区2,结束返回。
在这里插入图片描述

二、 jvm的类加载器

1.类的生命周期

在这里插入图片描述
类的加载周期分为七步,加载过程分为五个步骤。在加载一个类

  1. 加载(Loading):找 Class 文件
  2. 验证(Verification):验证格式、依赖
  3. 准备(Preparation):静态字段、方法表
  4. 解析(Resolution):符号解析为引用
  5. 初始化(Initialization):构造器、静态变 量赋值、静态代码块
  6. 使用(Using)
  7. 卸载(Unloading)

2.类的加载时期

  1. 当虚拟机启动时,初始化用户指定的主类,就是启动执行的 main 方法所在的类;
  2. 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类,就是 new 一个类的时候要初始化;
  3. 当遇到调用静态方法的指令时,初始化该静态方法所在的类;
  4. 当遇到访问静态字段的指令时,初始化该静态字段所在的类;
  5. 子类的初始化会触发父类的初始化;
  6. 如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化, 会触发该接口的初始化;
  7. 使用反射 API 对某个类进行反射调用时,初始化这个类,其实跟前面一样,反射调用 要么是已经有实例了,要么是静态方法,都需要初始化;
  8. 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。

3.类加载器

java的类加载器使用的双亲委派机制,即先有父类加载器进行加载,父类无法加载再由自己加载。这样的机制是为了避免类的重复加载。
在这里插入图片描述
三类加载器:

  1. 启动类加载器(BootstrapClassLoader) 加载根目录下的jar
  2. 扩展类加载器(ExtClassLoader) 在exc目录下的jar包
  3. 应用类加载器(AppClassLoader)

三、jvm的内存模型

1.jvm内存结构

1.每个线程都只能访问自己的线程栈。
2.每个线程都不能访问(看不见)其他线程的局部变量。
3.所有原生类型的局部变量都存储在线程栈中,因此对其他线程是不可见的。
4.线程可以将一个原生变量值的副本传给另一个线程,但不能共享原生局部变量本身。
5.堆内存中包含了 Java 代码中创建的所有对象,不管是哪个线程创建的。 其中也涵盖了包装类型 (例如 Byte,Integer,Long 等)。
6.不管是创建一个对象并将其赋值给局部变量, 还是赋值给另一个对象的成员变量, 创建的对象都 会被保存到堆内存中。

2.jvm的整体结构

1.jvm内存的整体结构

在这里插入图片描述
1.每启动一个线程,JVM 就会在栈空间栈分 配对应的 线程栈, 比如 1MB 的空间(- Xss1m)。
2.线程栈也叫做 Java 方法栈。 如果使用了 JNI 方法,则会分配一个单独的本地方法栈 (Native Stack)。
3.线程执行过程中,一般会有多个方法组成调 用栈(Stack Trace), 比如 A 调用 B,B 调用 C。。。每执行到一个方法,就会创建对应的栈帧(Frame)。

2.jvm栈内存结构

在这里插入图片描述
栈帧是一个逻辑上的概念,具体的大小在一个方法编写完成后基本上就能确定。比如返回值 需要有一个空间存放吧,每个 局部变量都需要对应的地址空间,此外还 有给指令使用的 操作数栈,以及 class 指 针(标识这个栈帧对应的是哪个类的方法, 指向非堆里面的 Class 对象)。

3,jvm的堆内存结构

在这里插入图片描述
堆内存是所有线程共用的内存空间,JVM 将Heap 内存分为年轻代(Young generation)和 老年代(Old generation, 也叫 Tenured)两部分。
一、年轻代还划分为 3 个内存池,新生代(Eden space)和存活区(Survivor space), 在大部分 GC 算法中有 2 个存活区(S0, S1),在我们可 以观察到的任何时刻,S0 和 S1 总有一个是空的, 但一般较小,也不浪费多少空间。Non-Heap 本质上还是 Heap,只是一般不归 GC 管理,里面划分为 3 个内存池。
二、Metaspace, 以前叫持久代(永久代, Permanent generation), Java8 换了个名字叫 Metaspace.CCS, Compressed Class Space, 存放 class 信 息的,和 Metaspace 有交叉。Code Cache, 存放 JIT 编译器编译后的本地机器 代码。

四、jvm的启动参数

在这里插入图片描述
以-开头为标准参数,所有的 JVM 都要实现这些参 数,并且向后兼容。

-D 设置系统属性。

以 -X 开头为非标准参数, 基本都是传给 JVM 的, 默认 JVM 实现这些参数的功能,但是并不保证所 有 JVM 实现都满足,且不保证向后兼容。 可以使 用 java -X 命令来查看当前 JVM 支持的非标准参 数。

以 –XX:开头为非稳定参数, 专门用于控制 JVM 的行为,跟具体的 JVM 实现有关,随时可能会在 下个版本取消。
-XX:±Flags 形式, ± 是对布尔值进行开关。 -XX:key=value 形式, 指定某个选项的值。

1.jvm启动参数–堆内存

1.Xmx, 指定最大堆内存。 如 -Xmx4g. 这只是限制了 Heap 部分的最大值为4g。这个内存不包括栈内存,也不包括堆外使用的内存。

2.-Xms, 指定堆内存空间的初始大小。 如 -Xms4g。 而且指定的内存大小,并 不是操作系统实际分配的初始值,而是GC先规划好,用到才分配。 专用服务 器上需要保持 –Xms 和 –Xmx 一致,否则应用刚启动可能就有好几个 FullGC。 当两者配置不一致时,堆内存扩容可能会导致性能抖动。

3.-Xmn, 等价于 -XX:NewSize,使用 G1 垃圾收集器 不应该 设置该选项,在其 他的某些业务场景下可以设置。官方建议设置为 -Xmx 的 1/2 ~ 1/4.

4.-XX:MaxPermSize=size, 这是 JDK1.7 之前使用的。Java8 默认允许的 Meta空间无限大,此参数无效。

5.-XX:MaxMetaspaceSize=size, Java8 默认不限制 Meta 空间, 一般不允许设 置该选项。

6.-XX:MaxDirectMemorySize=size,系统可以使用的最大堆外内存,这个参 数跟 -Dsun.nio.MaxDirectMemorySize 效果相同。

7.-Xss, 设置每个线程栈的字节数。 例如 -Xss1m 指定线程栈为 1MB,与- XX:ThreadStackSize=1m 等价

2.jvm启动参数–GC相关

1.-XX:+UseG1GC:使用 G1 垃圾回收器

2.-XX:+UseConcMarkSweepGC:使用 CMS 垃圾回收器

3 -XX:+UseSerialGC:使用串行垃圾回收器

  1. -XX:+UseParallelGC:使用并行垃圾回收器

3.jvm启动参数–分析诊断

1.-XX:±HeapDumpOnOutOfMemoryError 选项, 当 OutOfMemoryError 产生,即内存溢出(堆内存或持久代)时,自动 Dump 堆内存。
示例用法: java -XX:+HeapDumpOnOutOfMemoryError -Xmx256m ConsumeHeap

2.-XX:HeapDumpPath 选项, 与 HeapDumpOnOutOfMemoryError 搭配使用, 指定内存溢出时 Dump 文件的目录。如果没有指定则默认为启动 Java 程序的工作目录。
示例用法: java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/ ConsumeHeap
自动 Dump 的 hprof 文件会存储到 /usr/local/ 目录下。

3.-XX:OnError 选项, 发生致命错误时(fatal error)执行的脚本。
例如, 写一个脚本来记录出错时间, 执行一些命令, 或者 curl 一下某个在线报警的 url. 示例用法:java -XX:OnError=“gdb - %p” MyApp
可以发现有一个 %p 的格式化字符串,表示进程 PID。

4.-XX:OnOutOfMemoryError 选项, 抛出 OutOfMemoryError 错误时执行的脚本。 -XX:ErrorFile=filename 选项, 致命错误的日志文件名,绝对路径或者相对路径。 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1506,远程调试

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值