JVM结构
类加载子系统: 类加载子系统加载类后,将类信息放到方法区,除了类信息外还有运行时常量池信息
java堆: 堆在启动时建立,存放所有java实例,堆空间所有线程共享
直接内存: NIO会使用直接内存,读写频繁的场合会考虑使用直接内存
垃圾回收系统: 垃圾回收系统会对方法区,java堆和直接内存进行回收
java栈: 每个线程都会有一个java栈,启动线程就创建栈,栈保存局部变量,方法参数
本地方法栈: 本地方法栈用于本地方法调用
PC寄存器: 每个线程创建一个PC寄存器
新生代: eden区 S0区(from区) S1区(to区)
对象先分配到eden区,在一次新生代后,如果对象还存活则进入S0或者S1区,每经过一次新生代回收,年龄就会加1,当年龄到一定程度后被认为是老年对象,进入老年代
SimpleHeap s1=new SimpleHeap(1);
SimpleHeap s2=new SimpleHeap(2);
-Xss 指定线程最大栈空间
局部变量表存在栈中,如果局部变量过多,每一次调用函数会占用更多的栈空间,最终导致嵌套可调用次数减少
jdk1.7前参数-XX:MaxPermSize 设置永久区的大小,jdk1.7之后使用-XX:MaxMetaspaceSize 设置元数据区的大小
常用JVM参数
-XX:+PringGC 只要遇到GC就会打印日志,打印详细信息:-XX:PringGCDetails
-XX:+PrintGCTimeStamps 输出GC发生时间
-XX:+PrintPrintGCApplicationConcurrentTime 打印应用程序执行时间
-XX:+PrintGCApplicationStoppedTime 打印应用程序由于GC产生的停顿时间
-XX:+PrintReferenceGC 跟踪软引用,弱引用,虚引用和FinaFinallize队列
-Xloggc:log/gc.log 打印日志到文件
堆参数设置
一般设置初始堆-Xms和最大堆-Xmx设置相等,有利于减少垃圾回收次数
-Xmn 设置新生代的大小,一般设置为整个堆空间的1/3或1/4
-XX:SurvivorRatio 设置新生代中Eden空间和from/to空间比例关系 eden/from=eden/to
-XX:SurvivorRatio设置后不生效:
原来,在HotSpot VM里,并行系的收集器(UseParallelGC / UseParallelOldGC)默认开启-XX:+UseAdaptiveSizePolicy, 这个配置会在每次Minor GC之后对From和To区进行自适应分配大小,而SurvivorRatio使用默认值8,设置成任何非8的数值都会无效。所以,我这个参数里面的-XX:+UseAdaptiveSizePolicy其实是画蛇添足了
垃圾回收算法
引用计数法, 标记压缩法, 标记清除法, 复制算法, 分代分区算法
新生代: 复制算法
老年代: 标记压缩算法,标记清除算法
软引用: GC未必会回收弱引用对象,当内存资源紧张的时候会回收
弱引用: GC每次发现都会回收
虚引用: 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收
垃圾回收器
串行收集器
新生代串行收集器
复制算法
单线程, 独占式, 进行回收的时候所有线程要停止工作 +XX:+UseSerialGC
老年代串行收集器:
标记压缩算法
较大应用程序会停顿很长时间
-XX:+UseSerialGC 新, 老年代都用串行收集器
-XX:+UseParNewGC 新生代用并行回收器, 老年代用串行
-XX:+UseParallelGC 新生代用ParaParallelGC, 老年代用串行
并行收集器
新生代ParNew回收器
复制算法
简单地用多线程代替单线程, 程序会停顿
-XX:+UseParNewGC 新生代用ParNew,老年代用串行
-XX:+UseConcMarkSweepGC 新生代用ParNew, 老年代用CMS
-XX:+ParallelGCThreads 指定回收线程数,一般和cpu数量相当
新生代ParallelGC回收器
复制算法
重要参数:
-XX:MaxGCPauseMillis: 最大垃圾收集停顿时间,如果设置得太小,会导致jvm新建一个较小的堆,加多垃圾回收频率,所以不是越小越好
-XX:GCTimeRatio: 默认值是19,意思是不超所1%的时间用于垃圾回收
-XX:+UseAdaptiveSizeProxy: 打开自适应GC策略,手工调整比较困难的时候,只要设置最大堆, 目标吞吐量, 停顿时间, 让虚拟机自己完成调优
老年代ParallelOldGC回收器
标记压缩算法
-XX:+UseParUseParallelGC 新生代用ParallelGC回收器,老年代用ParallelOldGC回收器
CMS收集器
主要关注系统停顿时间
使用标记清除算法,多线程垃圾回收器,非独占式
初始标记(独占), 并发标记, 预清理, 重新标记(独占), 并发清除, 并发重置
启用CMS垃圾回收器 -XX:+UseConcMarkSweepGC
-XX:CMSSInitiatingOccupancyFraction 指定回收阈值,默认是68,当老年代空间使用率达到68会执行一次回收,如果内存增长快,在CMS过程中已经出现了内存不足情况,这个时候CMS会失败,虚拟机自动启动老年代的串行收集器,让程序停顿,直到垃圾回收完成
当执行标记清除算法后,会存在不完整的内存碎片,需要用-XX:+UseCMSCompactAtFullCollection设置当进行多少次CMS回收后,进行一次内存压缩
G1收集器
新生代GC, 并发标记周期(初始标记, 根区域扫描, 并发标记, 重新标记, 独占清理, 并发清理阶段), 混合回收(), 需要则进行FullGC
G1会优先回收垃圾比例较高的区域
-XX:+UseG1GC 打开G1收集器开关
-XX:MaxGCPauseMillis 指定目标最大停顿时间
-XX:ParallelGCThreads 设置并行回收时,GC工作线程数量
大对象当Eden空间不够时,会直接进入老年代,但是体积不是太大的对象有可能优先在TLAB中分配
不推荐使用Finalize()原因
性能监控工具
系统性能监控:top, vmstat 监控内存和cpu, iostat 监控IO
jvm性能监控工具
jstat -gc 20212 查看各个空间的情况
jstat -gccause 20212 查看最近GC的原因
jinfo -flag MaxTenuringThreshold 20212 查看某个参数的设置值,还可以动态开关参数jinfo -flag +PrintGCDetails 20212**
jmap -histo 20212 > D:\aaa.txt 获取对象统计信息
jmap -dump:format=b,file=D:\aa.hprof 20212 生成堆快照,然后用jdk自带工具jvisualvm打开hprof文件可以看到哪个对象很大,帮助定位问题
jmap -finalizerinfo 20212 查看对象有没有堆积在finalizer队列中
jstack -l 16016 > D:\d.txt 查看死锁原因
分配的堆空间太小
锁与并发