JVM调优

JVM 调优的原则
1、大多数的java应用不需要GC调优,GC调优是最后的手段。
2、大部分需要GC调优的,不是参数问题,是代码问题。实际中,根据GC优化代码比优化GC参数要多得多;

JVM调优的目的

并不会显著的提高系统性能,JVM调优,调的是稳定。
达到使用较小的内存占用来获得较高的吞吐量或者较低的延迟。

JVM调优的指标

内存占用:系统运行时,JVM需要的内存。
延迟:系统运行过程中由于垃圾收集引起的暂停时间。
吞吐量:单位时间内完成的任务数量。

JVM调优方法和关键参数

堆为什么要分代?

将生命周期不同的对象放在相应代,可以采取不同的垃圾回收方式,可以提高回收效率。

如何进行分代的?

 

JVM分为三个代:新生代(1份大小)、老年代(2份大小)和持久代(JDK8中已经把持久代去掉了,取而代之的元空间。元空间占用的是本地内存,不再占用虚拟机内存。)。持久代主要存放的是Java类的类信息,与垃圾回收关系不大。

什么情况下会触发垃圾回收?

GC分为:Minor GC和Full GC(对整个堆进行整理,包括Young、Tenured和Perm)。
无论是Minor或FullGC,都会导致stop-the-world,只有GC进程允许以进行垃圾回收,因此如果垃圾回收时间较长,部分web或socket程序,当终端连接的时候会报connetTimeOut或readTimeOut异常。

Full GC的触发?(内存泄漏是一个重要触发点)

1.老年代空间不足。2. 持久代或元空间不足。3. System.gc() 被调用。4. 上一次GC之后Heap的各域分配策略动态变化。 

Minor GC的触发?

Eden区满时,即申请一个对象时,发现eden区不够用,则触发一次MinorGC。

新生代

每次Minor gc时都会有大批对象死去,只有少量存活,那就选用“复制算法”,只需要付出少量存活对象的复制成本就可以完成收集。
Eden区位于Java堆的年轻代,是新对象分配内存的地方,由于堆是所有线程共享的,因此在堆上分配内存需要加锁。
新生代分为三个区,Eden:From:To = 8:1:1。当进行minor GC时,Eden区存活的对象全移到To区,而From区中,当达到一定值的对象会移到年老代中,没有达到阈值的复制到To区,经过GC后,Eden和From被清空。之后,From和To交换角色,To区始终是空的。且新的From区中对象年龄加1。

老年代

因为对象存活率高或对象比较大,“标记-整理”算法来进行回收,可以避免过度的复制移动和内存碎片。

对象所处分区
(1) 对象首次被创建时, 会放在新生代的eden区。
(2) 对象年龄到达设置的阈值。
-XX:MaxTenuringThreshold=15 (默认),熬过15次gc,对象就能进入老年代, 是充分不必要条件。
(3) 动态年龄判断
-XX:TargetSurvivorRatio=50 (默认),即当survivor区GC后使用率超过这个值。
当 年龄1 + 年龄2 + 年龄n的多个对象总和超过Survivor区的50%,那就会把年龄n以上的对象都放入老年代。
(4) 大对象直接进入老年代。防止大的对象来回复制,影响回收性能。
-XX:PretenureSizeThreshold (默认值是0,意味着任何对象都会现在新生代分配内存。) 即对象的大小大于此值, 直接在老年代分配, 此参数只对串行回收器以及ParNew回收有效, 而对ParallelGC回收器无效。

 对象可以在栈上分配吗?

可以,JVM允许将线程私有的对象分配在栈上,而不是分配在堆上。分配在栈上的好处是可以在函数调用结束后自行销毁,而不需要垃圾回收器的介入,从而提高系统性能。
栈上分配只是JVM虚拟机提供的一种优化技术,对象主要还是分配在堆上的。
栈上分配也是有前提的,需要进行逃逸分析,逃逸分析是指判断对象的作用域是否有可能逃逸出函数体。

原文地址:https://www.cnblogs.com/shijianchuzhenzhi/p/13219962.html