https://youzhixueyuan.com/jvm-performance-optimization.html
https://youzhixueyuan.com/jvm-garbage-collection-algorithm.html
https://youzhixueyuan.com/jvm-garbage-collector.html
https://blog.csdn.net/wfh6732/article/details/57422967
-
JVM内存模型:
栈区:栈可分为虚拟机栈和本地栈
堆区:堆可分为新生代和老年代 新生代可分为 Eden区和两个Survivor区
方法区:也被称为永久代,存储加载的类信息,常量静态变量,
堆区:java虚拟机锁管理内存最大的一块,被所有线程共享,
平常所说的垃圾回收主要发生在堆区
虚拟机栈:线程私有,其中又被分为局部变量表,操作数栈,动态连接,方法出口等 -
JVM内存参数:
-Xms设置堆的最小空间大小。
-Xmx设置堆的最大空间大小。
-Xmn:设置年轻代大小
-XX:NewSize设置新生代最小空间大小。
-XX:MaxNewSize设置新生代最大空间大小。
-XX:PermSize设置永久代最小空间大小。
-XX:MaxPermSize设置永久代最大空间大小。
-Xss设置每个线程的堆栈大小
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。 -
垃圾回收算法:
1.标记清除 清除所有未被标记的对象
适用于存活对象较多的情况(老年代)
2.标记复制 存活对象较少的情况下 适用于新生代
3.标记压缩 存活较少 垃圾对象较多 适用于老年代 -
垃圾回收 分代收集算法
新生代: 新生代存活率低 用标记复制
老年代:存活率高,空间少 标记清除或标记压缩 -
一个对象的创建到消亡的过程
1)新产生的对象优先分配在Eden区(除非配置了-XX:PretenureSizeThreshold,大于该值的对象会直接进入年老代);
2)当Eden区满了或放不下了,这时候其中存活的对象会复制到from区。
这里,需要注意的是,如果存活下来的对象from区都放不下,则这些存活下来的对象全部进入年老代。之后Eden区的内存全部回收掉。
3)之后产生的对象继续分配在Eden区,当Eden区又满了或放不下了,这时候将会把Eden区和from区存活下来的对象复制到to区(同理,如果存活下来的对象to区都放不下,则这些存活下来的对象全部进入年老代),之后回收掉Eden区和from区的所有内存。
4)如上这样,会有很多对象会被复制很多次(每复制一次,对象的年龄就+1),默认情况下,当对象被复制了15次(这个次数可以通过:-XX:MaxTenuringThreshold来配置),就会进入年老代了。
5)当年老代满了或者存放不下将要进入年老代的存活对象的时候,就会发生一次Full GC(这个是我们最需要减少的,因为耗时很严重)。 -
垃圾回收有两种类型:Minor GC 和 Full GC。
1 Minor GC
对新生代进行回收,不影响老年代, minorGC非常频繁.
2 Full GC 也叫 Major GC
对整个堆进行回收,包括新生代,老年代, 回收速度比较慢
调用major GC的原因: 老年代满 永久代满 调用system.gc() -
垃圾回收器:
常见的有三种:
新生代垃圾回收器:
serial(新生代串行回收器) PraNew(新生代并行收集器) Parallel Scavenge(并行回收)
年老代垃圾回收器:
Serial Old(老年大串行回收器) Parallel Old(老年代并行回收器) CMS(Current Mark Sweep)
新生代和年老代垃圾回收器: G1回收器 -
Full GC的原因
1)老年代被写满
2)永久代内存不足
3)System.gc()被显示调用 -
jvm性能调优的方法和步骤
对 JVM的系统调优主要目的是减少GC频率和FullGC的次数
系统崩溃前的一些现象,
①垃圾回收用时越来越长,②Full GC越来越多 ③老年代内存越来越大
方法和步骤:
(1)监控GC状态,使用各种JVM工具(Jmap +mat),监控当前日志, JVM参数,分析内存快照,和GC日志和GC时间决定是否进行优化
(2)生成dump文件
-XX :+HeapDumpOnOutOfMemoryError //发生内存溢出时 导出内存映像
-XX:HeapDumpPath=./ //导出位置 (这样写时当前路径)
(3)分析dump文件 (工具 MAT visualVM)
(4) 分析是否需要优化: 如果各项参数设置合理,没有出现超时日志,GC频率不高,耗时不长,没有必要优化
一般来说满足下面指标是不需要优化的:
①MinorGC 执行时间不到50ms
② MinorGC 不频繁 10秒1次
③ FullGC 时间不到1s
④ FullGC 频率低 低于十分钟一次
(5)调整GC类型和内存分配
内存分配过大或者过小,或者采用的GC收集器比较慢,则优先调整这些参数,
不断的分析和调整,找出最合适的参数. -
JVM调优参数参考
1)针对JVM堆的设置,一般可通过-Xms -Xmx 限定其最小最大值,为了防止垃圾收集器在最小最大之间收缩堆,而产生的额外时间,通常把最小和最大值设置为相同的值
2)新生代和老年代根据默认的比例1:2分配内存, 可以通过调整二者之间的比率NewRadio来调整二者之间的大小,也可以针对回收代,比如年轻代. 通过 -XX:newSize -XX:MaxNewSize来设置其绝对大小。同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小。
3)年轻代和年老代设置多大才算合理
1\更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC
2\更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率,如何选择应该依赖应用程序对象生命周期的分布情况: 如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性。
在抉择时应该根 据以下两点:
(1)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认1:2也是这个道理 。
(2)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。
在配置较好的机器上(比如多核、大内存),可以为年老代选择并行收集算法: -XX:+UseParallelOldGC 。
5.线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。