一、 常用参数的设置
- -xms -xmx 设置堆的大小。
- -xmn设置年轻代,默认是堆大小的3/8.
- 一个gui程序最好在10-20s内进行gc,在半秒内完成。
二、常用的监控命令
- jstat -<option> <pid> time:间隔多长时间打印gc信息
查看jvm运行状态,垃圾收集,内存,类装载,等等 - jps [option] [hostid]
ex: jps -v 输出启动时的jvm参数
jps和ps命令类似 - jmap
三、垃圾收集器
- Serial(新生代)
- 单线程、新生代(复制)、必须暂停其他所有的工作线程。
- Serial 是虚拟机运行在Client模式下的默认新生代手气器。
- ParNew(新生代)
- 是Serial的多线程版本(算法,回收策略等都一样),单个cpu下不能比Serial有好的效果,存在线程交互开销,两个CPU也不能保证
- 是和CMS配合使用的新生代收集器
- 默认开启的收集线程数和CPU数量相等
- Parallel Scavenge (新生代)
- 复制算法
- 多线程
- 目标是达到一个可控的吞吐量(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间))
- 可以设置吞吐量和最大垃圾收集停顿时间,时间太小系统会吧新生代的容量减少, GC的停顿时间的缩短是以牺牲吞吐量和新生代空间换来的。
- 自适应调节策略是和ParNew的最大区别
- Serial old (标记-整理)
- 单线程
- 给client模式下的虚拟机使用
- Parallel Old(标记-整理)
- 是Parallel Scavenge的老年代版本
- 多线程
- JDK 1.6开始提供,是JDK1.8的默认收集器
- CMS (标记-清除)
- 并发收集,低停顿
- 获取最短停顿时间为目标
- 标记清除过程
(1)初始标记 标记一下能关联到GC Roots的对象,速度很快
(2)并发标记(可以和用户线程一起工作) GC Roots的Tracing过程
(3)重新标记 为了修正因为用户线程继续运行导致标记产生动荡的那一部分对象的标记记录
(4)并发清除(可以和用户线程一起工作)
(1)(3)仍需要Stop the world
(5)cms对cpu资源比较敏感,并发过程会占用一部分资源导致应用程序变慢,总的吞吐量会降低,默认回收线程数(cpu数量+3)/4,cpu少于四个的时候,cms对用户线程影响很大
(6)cms会产生浮动垃圾 (7)会有碎片产生,在进行full gc 的时候进行碎片整理
- G1(标记整理)
G1把整个堆划分成多个大小相等的Region,保留着年轻代和老年代的区分,但是已经不是物理隔离了,它们都是一部分Region(不不要连续)的集合
- 分代收集
- 并行与并发
- 空间整理
- 可预测的停顿 避免在整个堆上进行垃圾回收,G1跟踪各个Region的垃圾堆积的价值大小在后天维护一个优先列表,根据允许的手机时间,优先回收价值最大的Region
- 收集器运作 (1)初始标记 标记GC Roots能关联到的对象
(2)并发数标记 可达性分析,找到存活的对象
(3)最终标记 (4)筛选标记 Region的垃圾堆积的价值大小排序,根据用户期望的停顿的时间来制定回收计划\
四、调优实战
五、类加载机制
- 类加载
- Java虚拟机规范并没有规定什么时候需要进行类的加载阶段,但是以下情况必须对类进行初始化
(1)使用new关键字实例化对象时、读取或者设置一个类的静态字段(不包含编译期常量)以及调用静态方法的时候,必须触发类加载的初始化过程(类加载过程最终阶段)。
(2)使用反射调用时
(3)当Java虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的类),虚拟机会先初始化这个主类
(4)初始化类的必须先初始化父类。 - 获取class引用有三种方式
(1)object 的 getclass() 需要出发类的初始化
(2)Class 类的 forName(name) , forName方法是Class类的一个static成员方法 需要触发类初始化
(3)字面量 .class 不需要初始化