第一章: Java虚拟机介绍

1.1 jvm分类

  1. Sun Classic VM : 世界上第一款商用的Java虚拟机
  2. Extract VM:准确试内存管理 编译器和解释器混合工作以及两级及时编译器
  3. HotSpot VM
  4. KVM: kilobyte 简单,轻量, 高度可移植。 在手机平台运行
  5. JRockit: BEA. 世界最快的Java虚拟机 优势 1.垃圾收集器。2. MissionControl 服务套件
  6. J9:
  7. Dalvik:
  8. Microsoft JVM:
  9. Azul VM Liquidj VM: 高性能的Java虚拟机
  10. TaobaoVM:

1.2 Java虚拟机内存管理

线程共享区:方法区,Java堆
线程独占区:程序计数器, 虚拟机栈,本地方法栈

image.png

1.2.1 程序计数器

  1. 当前程序执行的字节码行号
  2. 程序计数器处于线程独占区
  3. 执行Java方法,计数器记录当前程序地址,native方法,记录undefined
  4. 此区域没有任何内存溢出

1.2.2 Java虚拟机栈

  1. 栈帧:
  2. 每个方法执行,都会创建一个栈帧
  3. 局部变量表:
  4. 存放编译期可知的各种基本数据类型,引用类型,returnAddress
  5. 大小:
  6. 递归的调用出现栈溢出:
  7. stackoverflowError:栈溢出
  8. OutOfMemery

1.2.3 Java虚拟机的本地方法栈

  1. 为虚拟机执行native方法的

1.2.4 Java虚拟机内存区域—堆区域

  1. 存放对象实例
  2. 垃圾收集器管理的主要区域
  3. 新生代。老年代

1.2.5 Java内存区域-方法区

  1. 1.存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据
  2. 2.方法区和永久代
  3. 3.垃圾回收在方法区的行为
  4. 4.异常的定义
  5. OutOfMemeryError

1.2.6 Java内存区域-直接内存和运行时常量池

  1. 1.
  2. String s1 = "abc";
  3. String s3 = new String("abc");
  4. s3.internal() 运行时常量
  5. 2.直接内存
  6. 能够分配堆外内存

1.2.7 对象在内存中的布局—对象的创建

image.png

第二章 垃圾回收机制-概述

2.1 如何判定对象为垃圾对象

  1. 1.引用计数法
  2. 2.可达性分析法

2.2 如何回收

  1. 1.回收的策略
  2. 标记-清除法
  3. 复制算法
  4. 标记-整理算法
  5. 分代收集算法
  6. 2.垃圾收集器
  7. Serial
  8. Parnew
  9. Cms
  10. G1

2.3 何时回收

2.3.1 引用计数法

  1. 垃圾回收-判断对象是否存活算法--引用计数法
  2. 在对象中添加引用计数器,当有地方引用这个对象的时候,引用计数器的值
  3. 就+1,当引用失效的时候,计数器的值就是-1
  4. 打印详细的GC信息
  5. -verbose:gc
  6. -xx:PrintGCDetails
  7. 代码:
  8. Main m1 = new Main()
  9. Main m2 = new Main()
  10. m1.instance = m2;
  11. m2.instance = m1;
  12. m1 = null;
  13. m2 = null;

2.3.2 可达性分析法

  1. 垃圾回收-判断对象是否存活算法--可达性分析法(主流)
  2. 作为GC Roots的对象
  3. 虚拟机栈
  4. 方法区的类属性所引用的对象
  5. 方法区中常量所引用的对象
  6. 本地方法栈中引用的对象

2.3.4 垃圾回收算法-标记清除算法

  1. 效率问题
  2. 空间问题
  3. 回收内存时导致内存不连续

2.3.5 垃圾回收算法-复制算法

  1. 内存资源极大浪费(内存空间只用一半)
  2. 堆:
  3. 新生代
  4. Eden:伊甸园
  5. Survivor:存活区
  6. Tenured Gen:
  7. 老年代
  8. 方法区

2.3.6 垃圾回收算法-标记整理清楚算法。分代收集算法

  1. 垃圾回收算法-标记整理清楚算法。分代收集算法
  2. 标记整理--回收老年代
  3. 分代收集算法--根据不同的分代采用不同的算法

2.3.7 垃圾收集器—Serial收集器(针对新生代)

  1. 最基本-发展最悠久
  2. 单线程垃圾收集器

2.3.8 垃圾收集器—parnew收集器

  1. 多线程垃圾收集器

2.3.9 垃圾收集器—Parallel收集器

  1. 复制算法(新生代收集器)
  2. 多线程收集器
  3. 可达到吞吐量:CPU用与运行用户代码的时间
  4. CPU消耗的总时间的比值
  5. 吞吐量 = (执行用户代码时间)/ (执行用户代码的时间 + 垃圾回收所占用的时间)
  6. -XX:MaxGCPauseMillis 垃圾收集器最大停顿的时间
  7. -XX:GCTimeRatio 吞吐量大小
  8. 0100

2.3.10 垃圾收集器—CMS收集器

  1. Concurrent Mark Sweep(并发标记清楚算法)
  2. 工作过程:
  3. 初始标记
  4. 并发标记
  5. 重新标记
  6. 并发清理
  7. 优点:
  8. 并发收集
  9. 低停顿
  10. 缺点:
  11. 占用大量的CPU资源
  12. 无法收集浮动垃圾
  13. 出现Concurrent Mode Failure
  14. 时间碎片

2.3.11 垃圾收集器—G1收集器

  1. 优势:
  2. 并行 并发
  3. 分代收集
  4. 空间整合
  5. 可预测的停顿
  6. 步骤:
  7. 初始标记
  8. 并发标记
  9. 最终标记
  10. 筛选回收

第三章 内存分配—概述

image.png
image.png

3.1 内存分配策略

  1. 内存分配策略
  2. 优先分配到Eden
  3. 大对象直接分配到老年代
  4. 长期存活的对象分配到老年代
  5. 空间分配担保
  6. 动态对象年龄判断

3.1.1 内存分配-Eden区域

  1. 打印详细的GC信息
  2. -verbose:gc
  3. -xx:PrintGCDetails
  4. 使用Serial算法
  5. -XX:+UserSerialGC
  6. 指定堆内存大小(20M)
  7. -Xms20M
  8. -Xmx20M
  9. 新生代内存大小
  10. -Xmn10M
  11. 限制Eden区的大小
  12. -XX:SurvivorRation=8

3.1.2 内存分配-大对象直接进入老年代

  1. 指定对象的大小(如果大小这个值,则直接进入老年代)
  2. --XX:PretenureSizeThreshold=6M
  3. (指定大对象为6M

3.1.3 内存分配-长期存活的对象进入老年代

  1. --XX:MaxTenuringThreshold 15(默认值为)

3.1.4 内存分配-空间分配担保

  1. -XX:+HandlePromotionFailure

3.1.5 内存分配-逃逸分析与栈上分配

  1. 逃逸分析:分析对象的作用域
  2. 引用的作用域仅在当前方法中有效,没有发生逃逸
  3. 引用成员变量的值,发生逃逸
  4. 代码:

3.2 虚拟机工具介绍

  1. jps
  2. jstat
  3. jinfo
  4. jmap
  5. jhat
  6. jstack
  7. jconsole

3.2.1 虚拟机工具-jps

  1. Java Process status
  2. 本地虚拟机唯一ID local virtual machine ID
  3. jps -l 类的全名
  4. jps -m 接收命令行参数
  5. jps -v 接收虚拟机参数

3.2.2 虚拟机工具-jstat

  1. 类加载。内存。垃圾收集 git编译信息
  2. jstat -gcutil 6692
  3. jstat -gcutil 6692 1000 10
  4. S0:Survivor0
  5. S1:Survivor1
  6. E:Eden
  7. O:Old
  8. M:Meta
  9. CCS:压缩类空间
  10. YGC:年轻代发生的GC次数
  11. YGCT:年轻代发生的GC次数的时间
  12. FGC:
  13. FGCT:
  14. GCT:

元空间本质和永久代本质类似
元空间不在虚拟机,在直接内存中
**

3.2.3 虚拟机工具-jinfo

  1. 实时查看和调整虚拟机的各项参数
  2. jinfo -flag UseSerialGC
  3. -XX

3.2.4 虚拟机工具-jmap

  1. 导出进程的快照信息 显示堆中的信息
  2. jmap -dump:format=b,file=~/a.bin pid
  3. jmap histo
  4. -XX:+HeapDumpOnOutOfMemoryError

3.2.5 虚拟机工具-jhat (Jvm heap Analysis Tool)

  1. dumpheap信息拷贝本地分析
  2. jmap -dump:format=b,file=d:\a.bin pid
  3. jhat d:\a.bin
  4. OQL的使用

3.2.6 虚拟机工具-jstack

  1. 生成线程栈快照
  2. 目的:导致线程长时间停留原因
  3. jstack -l pid
  4. Map<Thread,StackTraceElemnt[]> m = Thread.getAllStackTraces();
  5. for( Map.Entry<Thread,StackTraceElemnt[]> en : m.entry.set) {
  6. }

3.2.7 可视化虚拟机工具-jconsole内存监控

3.2.8 可视化虚拟机工具-jconsole线程监控

3.2.9 可视化虚拟机工具-jconsole线程死锁监控

第四章 性能调优

  1. 知识
  2. 工具
  3. 数据
  4. 经验
  5. 性能调优--案例1
  6. 性能调优--案例2
  7. Class文件简介和发展历史
  8. Helle.java
  9. javac Helle.java
  10. 生成Helle.class
  11. 运行Java程序
  12. java Helle

第五章 class文件结构

image.png

image.png

第六章 类加载过程

image.png
image.png

6.1 类加载的过程—加载

  1. 通过一个类的全限定名来获取定义此类的二进制流
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的Class对象,作为这个类的各种数据的访问入口
  4. 加载源:
  5. 文件
  6. class文件
  7. jar文件
  8. 网络
  9. 计算生成一个二进制流
  10. 由其他文件生成
  11. 数据库

6.2 类加载的过程—验证

  1. 为了确保class文件的字节流中包含的信息复合当前虚拟机的要求并不回危害虚拟机自身的安全
  2. 文件格式验证
  3. 元数据验证
  4. 字节码验证
  5. 符号引用验证

6.3 类加载的过程—准备

  1. 为类变量分配内存并设置变量的初始值(给变量初始化为默认的值)
  2. 这些变量使用的内存都将在方法区中进行分配

6.4 类加载的过程—解析

  1. 虚拟机将常量池中的符号引用替换为直接引用的过程
  2. 类或者接口的解析
  3. 字段解析
  4. 类方法解析
  5. 接口解析

6.5 类加载的过程—初始化

  1. 类加载的最后一步
  2. 执行<clinit>方法的过程
  3. 4.如果多个线程同时初始化一个类,只有一个线程执行这个类的init方法
  4. 问题:多线程执行static 代码块时,容易阻塞

6.6 类加载器

  1. 1.通过一个类的全限定名来获取描述
  2. 2.只有被同一个类加载器加载才相等

6.6.1 载器分类

  1. 启动类加载器
  2. C+实现,时虚拟机的一部分。lib
  3. 扩展类加载器
  4. lib/ext
  5. 应用程序加载器
  6. 加载用户类路径
  7. 自定义类加载器
  8. 优势:高度的灵活
  9. 通过自定义类加载器可以实现热部署
  10. 代码加密

6.6.2 自定义类加载器

  1. 1.定一个类,继承classloader
  2. 2.重写loadClass方法
  3. 3.实例
  4. ClassLoader mycl = new ClassLoader(){
  5. public Class<?> loadClass(String name) throws {
  6. String filename = name.substring(name.lastIndexOf(".") + 1) + ".class";
  7. InputStream ins = getClass().getResouceAsStream(fileName);
  8. if ( ins == null ) {
  9. return super.loadClass(name);
  10. }
  11. byte [] buff = new byte[ins.available()];
  12. ins.read(buff);
  13. return defineClass(name, buff, 0, buff.length);
  14. }
  15. }
  16. Class c = mycl.loadClass("com.root.Test").newInstance();