JVM参数命令:
-Xmx20M //指定堆内存最大为20M
-Xms20M //指定堆内存最小为20M
-Xmn10M //指定新生代内存为10M
-XX:SurvivorRatio=8 // 指定Eden占8份 Eden : survivor = 8
-XX:PretenureSizeThreshold=7M // 指定对象直接进入老年代的大小
-XX:+HandlePromotionFailure // 是否开启空间分配担保, +开启, -不关闭 promotion:提升
-XX:+HeapDumpOnOutOfMemoryError // 打印虚拟机内在溢出时的快照,感觉用得不多
-XX:HeapDumpPath=/path //指定快照的路径
-verbose:gc
-xx:+PrintGCDetail //打印垃圾回收日志信息:
-XX:+UseSerialGC //指定使用Serial收集器
-XX:+TraceClassLoading //用于追踪类的加载信息并打印
虚拟机分类:
sun/oracle: Sun Classic VM, Exact VM, HotSpot VM, KVM(Kilobyte), JRockit
IBM: J9
Azul Systems: Azul VM
BEA: Liquid VM
微软:Microsoft JVM
判断回收对象算法:
引用计数算法:基本不用,对象自身有标记是否有被引用,可能造成对象不能回收,在堆内存中存在对象引用对象的情况。
可达性算法:GCRoot,到对象引用,完成的引用链
可用为GCRoot对象:虚拟机栈,方法区的类属性所引用的对象,方法区中常量所引用的对象,本地方法栈中引用的对象。
垃圾收集算法总结:
标记-清除:其它三种算法的基础,标记要回收的对象,然后清除掉,可能造成空间碎片,不规则的内存,多用于老年代
复制算法:主要运用在新生代内存中,把内存划分为 eden, survivor A,survivor B, tenured gen, 复制存活对象到survivor A中标记存活次数,清除掉eden中垃圾对象第二次垃圾回收时,把存活对象复制到 B中,并把A中存活的对象也复制过来,标记存活次数,清除eden和A,存活次数达到20次,就复制对象到tenured gen
标记-整理:主要作用到老年代,在内存中划分一条线,把存活的移到一边,把清除的移到一边,清除清除区。
分代收集算法:区分新生代用复制算法,老年代用标记-整理算法。
垃圾收集器:
Serial:单线程,最基本,最悠久的;多应用于桌面程序(客户端),针对老年代。
Parnew:可看作多线程的Serial收集器。
Parallel Scavenge: 复制算法(新生代收集器),多线程收集器,可控制的吞吐量
吞吐量:CPU执行用户代码时间 / (CPU执行用户代码时间 + CPU回收垃圾的时间)
-XX:MaxGCPauseMills 垃圾收集器停顿时间
-XX:GCTimeRatio 吞吐量大小 (0,100)
CMS:Concurrent Mark Sweep 多用回收老年代
工作过程:
初始标记(GCRoot回收对象)->并发标记->重新标记(对并发标记的修整)->并发清理
优点:并发收集,低停顿
缺点:占用CPU资源过大,无法处理浮动垃圾,出现Concurrent Mark Failure(清除过程中可能创建的对象内存不足),空间碎片
G1:可能用到JDK9
步骤:初始标记-并发标记-最终标记-筛选标记
Serial New 收集器是针对新生代的收集器,采用的是复制算法
Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理
Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法
Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理
Parallel Old(并行)收集器,针对老年代,标记整理
CMS收集器,基于标记清理
G1收集器:整体上是基于标记 整理 ,局部采用复制
内存分配:
-对象优先分配到Eden区
-大对象直接进入老年代 // JVM会判断这个对象不是朝生夕死的,使用 -XX:-HandlePromotionFailure 关闭
-空间分配担保 // 默认启用,当分配到eden内在不足时,对象可移到老年代内存中,老年代会先衡量自身能否分配
-逃逸分析与栈上分配 // 可提高性能
-逃逸分析:分析对象的作用域,如果只作用在当前方法体内对象,就是非逃逸对象,可以栈上分配
-调用Systen.gc()时,可能会把对象移到老年代?
分析工具:
-jps -m -v 显示指定系统内所有的 HotSpot 虚拟机进程
-jstat 可以观察到classloader,compiler,gc相关信息。可以时时监控资源和性能
-jinfo 显示虚拟机配置信息
-jmap 生成虚拟机的内存转储快照(heapdump 文件)
-jstack 显示虚拟机的线程快照
性能调优:
-知识
-工具
-数据
-经验
Class文件格式:
魔数:
-CA CF BA BE // class文件的
JDK1.8 = 52
常量池:
类加载器:
类加载过程:
加载:加载Class文件的二进制数据到内存中,将其放在运行时数据区的方法区内,然后在内存中创建一个 java.lang.Class对象 用来封装类在方法区内的数据结构
-java程序“首次主动使用”每个类或接口时,才会被初始化这个类或接口。
主动使用情况
-创建类的实例
-访问某个类或接口的的静态变量,或者对该静态变量赋值,注意 访问静态变量只有直接定义了该静态变量的类才会被初始化,
使用的类有被加载,未初始化,可使用 -XX:+TraceClassLoading 用于追踪类的加载信息并打印
-调用类的静态方法
-反射
-初始化这个类的子类时,这个父类也会是主动使用;当一个类被初始化,他的所父类及父类的父类全部会被初始化
-java虚拟机启动时被标记为启动类的类 运行时main方法所在的类会被加载并初始化
-JDK1.7开始提供的动态语言支持
java.lang.invoke.MethodHandle 实例的解析结果为REF_getStatic,REF_putStatic,REF_involeStatic句柄对应的类没有初始化,即初始化
连接:
-验证:类文件结构正确性
-准备:给类的静态属性分配空间,并赋予默认值
-解析:将类的符号引用改为直接引用(类指针)
初始化:把类的静态属性赋予实际的初始值
###常量的本质:在编译期能确定的常量在编译阶段会存入到调用这个常量的方法所在类的常量池中,本质上调用类并没有直接引用到定义常量的类,因此并不会触发定义该常量的类的初始化。而 运行期常量 会初始化定义此常量所有的类
###数组的本质:数组是一种特殊的类型,是JVM在运行期创建的,创建某个类型的数组时,并不会初始化该类(此时数组可能会空)。数组的父类是Object;二维数组本质是一维数组的一维数组。
反编译助记符:
ldc: 表示将 int, float 或是 String 类型的常量值从常量池中推送到栈顶
bipush: 表示将单字节(-128- +127)的常量值推送到栈顶
sipush: 表示
iconst_m1 ~ iconst_5: 表示将int为-1-5 的常量推送到栈顶 iconst_m1,iconst_0等,在 ICONST 类中
anewarray: 表示把引用类型(如类,接口,数组)数组,并将其引用推入栈顶
newarray: 表示把基本类型(int short char等)数组,并将其引用推入栈顶