JVM学习(6)-- 性能优化及总结

目录

性能优化及总结

JVM图解

GC优化

垃圾收集发生的时机

实验

GC日志文件分析工具

调优最佳指南G1(借鉴)

高并发场景分析

JVM性能优化指南

常见的问题及解答

内存泄露和内存溢出的区别

youngGC会有stw吗

major gc和full gc的区别

G1与CMS的区别是什么

什么是直接内存

垃圾判断的方式

不可达的对象一定要被回收吗?

f方法区中的无用类回收

不同的引用

为什么要区分新生代和老年代?


性能优化及总结

JVM图解

执行引擎:用于执行JVM字节码指令

主要有两种实现方式

(1)将输入的字节码指令在加载时或执行时翻译成另外一种虚拟机指令(解释执行)

(2)将输入的字节码指令在加载或执行时翻译成宿主主机本地CPU指令集(即时编译)

GC优化

内存被使用之后,难免会有不够用或达到设定值的时候,此时就需要对内存空间进行垃圾回收

垃圾收集发生的时机

GC是有JVM自动完成的,根据JVM的系统环境而定,所以时机是不确定的,当然我们也可以手动进行垃圾回收,比如调用System.gc()只是通知要回收,什么时候回收由JVM决定

一般以下几种情况会发生垃圾回收

  • 当Eden区或者s区不够用了
  • 老年代空间不够用了
  • 方法区空间不够用了
  • System.gc();

实验

1.得到GC日志文件 博主用的是eclipse 在eclipse根目录下找到eclipse.ini 加上

-verbose:gc 
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps 
-Xloggc:gc.log

再启动Tomcat后会在eclipse根目录下产生GC日志

理解日志格式  https://blogs.oracle.com/poonam/understanding-g1-gc-logs

GC日志文件分析工具

https://gceasy.io

调优最佳指南G1(借鉴)

(1) 不要手动设置新生代和老年代的大小,只要设置整个堆的大小
 
G1 收集器在运行过程中,会自己调整新生代和老年代的大小
其实是通过 adapt 代的大小来调整对象晋升的速度和年龄,从而达到为收集器设置的暂停时间目标 如果手动设置了大小就意味着放弃了 G1 的自动调优
 
(2) 不断调优暂停时间目标
 
一般情况下这个值设置到 100ms 或者 200ms 都是可以的 ( 不同情况下会不一样 ) ,但如果设置成 50ms 不太合理。暂停时间设置的太短,就会导致出现 G1 跟不上垃圾产生的速度。最终退化成 FullGC 。所以 对这个参数的调优是一个持续的过程,逐步调整到最佳状态。暂停时间只是一个目标,并不能总是得到 满足。
 
(3) 使用 -XX:ConcGCThreads=n 来增加标记线程的数量
 
IHOP 如果阀值设置过高,可能会遇到转移失败的风险,比如对象进行转移时空间不足。如果阀值设置过 低,就会使标记周期运行过于频繁,并且有可能混合收集期回收不到空间。 IHOP 值如果设置合理,但是在并发周期时间过长时,可以尝试增加并发线程数,调高 ConcGCThreads
 
(4)MixedGC 调优
 
-XX:InitiatingHeapOccupancyPercent
-XX:G1MixedGCLiveThresholdPercent
-XX:G1MixedGCCountTarger
-XX:G1OldCSetRegionThresholdPercent
 
(5) 适当增加堆内存大小
 

高并发场景分析

JVM性能优化指南

常见的问题及解答

内存泄露和内存溢出的区别

内存泄漏是指不再使用的对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费。 内存泄漏很容易导致内存溢出,但内存溢出不一定是内存泄漏导致的。

youngGC会有stw吗

不管什么 GC ,都会发送 stop-the-world ,区别是发生的时间长短。而这个时间跟垃圾收集器又有关 系, Serial PartNew Parallel Scavenge 收集器无论是串行还是并行,都会挂起用户线程,而 CMS G1 在并发标记时,是不会挂起用户线程的,但其它时候一样会挂起用户线程, stop the world 的时 间相对来说就小很多了。

major gcfull gc的区别

Major Gc 在很多参考资料中是等价于 Full GC 的,我们也可以发现很多性能监测工具中只有 Minor GC Full GC 。一般情况下,一次 Full GC 将会对年轻代、老年代、元空间以及堆外内存进行垃圾回收。触 Full GC 的原因有很多:当年轻代晋升到老年代的对象大小,并比目前老年代剩余的空间大小还要大 时,会触发 Full GC ;当老年代的空间使用率超过某阈值时,会触发 Full GC ;当元空间不足时( JDK1.7 永久代不足),也会触发 Full GC ;当调用 System.gc() 也会安排一次 Full GC

G1CMS的区别是什么

CMS 主要集中在老年代的回收,而 G1 集中在分代回收,包括了年轻代的 Young GC 以及老年代的 Mix GC G1 使用了 Region 方式对堆内存进行了划分,且基于标记整理算法实现,整体减少了垃圾碎片的 产生;在初始化标记阶段,搜索可达对象使用到的 Card Table ,其实现方式不一样。

什么是直接内存

Java NIO 库允许 Java 程序使用直接内存。直接内存是在 java 堆外的、直接向系统申请的内存空间。通 常访问直接内存的速度会优于 Java 堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内 存。由于直接内存在 java 堆外,因此它的大小不会直接受限于 Xmx 指定的最大堆大小,但是系统内存是 有限的, Java 堆和直接内存的总和依然受限于操作系统能给出的最大内存。

垃圾判断的方式

引用计数法:指的是如果某个地方引用了这个对象就 +1 ,如果失效了就 -1 ,当为 0 就会回收但是 JVM 有用这种方式,因为无法判定相互循环引用( A 引用 B,B 引用 A )的情况
引用链法:通过一种 GC ROOT 的对象(方法区中静态变量引用的对象等 -static 变量)来判断,如果有 一条链能够到达 GC ROOT 就说明,不能到达 GC ROOT 就说明可以回收

不可达的对象一定要被回收吗?

即使在可达性分析法中不可达的对象,也并非是 非死不可 的,这时候它们暂时处于 缓刑阶段 ,要真 正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行 一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。 被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个 对象建立关联,否则就会被真的回收。

f方法区中的无用类回收

方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢?
判定一个常量是否是 废弃常量 比较简单,而要判定一个类是否是 无用的类 的条件则相对苛刻许多。 类需要同时满足下面 3 个条件才能算是 无用的类
  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
  • 加载该类的 ClassLoader 已经被回收。
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方 法。
     
    虚拟机可以对满足上述 3 个条件的无用类进行回收,这里说的仅仅是 可以 ,而并不是和对象一样不使 用了就会必然被回收。

不同的引用

JDK1.2以后,Java对引用进行了扩充:强引用、软引用、弱引用和虚引用

为什么要区分新生代和老年代?

当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不 同将内存分为几块。一般将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合 适的垃圾收集算法。
比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制 成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分 配担保,所以我们必须选择 标记 - 清除 标记 - 整理 算法进行垃圾收集。

猜你喜欢

转载自blog.csdn.net/baidu_41922630/article/details/104859886