jvm 使用CMS时FGC每次会跳2次
现象使用jstat -gc观察CMS FullGC的时候,发现每次到阈值回收的时候,FGC每次会跳2次:
123456789101112 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT68096.0 68096.0 0.0 16853.2 545344.0 371165.3 8755648.0 5890791.6 62312.0 59746.5 7076.0 6608.5 43879 1312.752 60 5.206 1317.95868096.0 68096.0 19377.9 0.0 545344.0 420827.3 8755648.0 5891528.9 62312.0 59746.5 7076.0 6608.5 43880 1312.785 60 5.206 1317.99168096.0 68096.0 0.0 ...
CMS回收器执行流程
CMS(Concurrent Mark Sweep)目标:获取最短回收停顿时间为目标的收集器。算法:"标记-清除"算法实现
CMS是老年代垃圾收集器,在收集过程中可以与用户线程并发操作。它可以与 Serial 收集器 和 Parallel New收集器搭配使用。CMS牺牲了系统的吞吐量来追求收集速度,适合追求垃圾收集速度的服务器上。可以通过JVM启动参数,来开启CMS:
-XX:+UseConcMarkSweepGC
牺牲吞吐量,追求收集速度是什么意思
其实实际使用过程中发现,CMS是将每次收集的时间减少,但是垃圾还是那么多,于是回收的工作方式就变成了跟吃自助餐常听到的一样"勤拿少取",就是每次回收时间短,也并不完全回收全部的垃圾,通过多次回来处理。
1.初始标记(CMS initial mark)单线程,标记新生代可达老年代的对象。为了收集应用程序的对象引用需要暂停应用程序线程,该阶段完成后,应用程序线程再次启动。
2.并发标记(CMS-concurrent-mark)在第一个阶段(Initial Mark)被暂停的应用线程将恢复运行 ...
CMS 问题定位与排查
起因最近排查一个历史老问题,历史问题就是大家都知道,但是没人愿意处理。线上节点 16 和 32 G 内存频繁的出现GC,并且由于 GC 还导至两个问题,1.CPU使用率在GC时变高,2.业务出现异常。这个问题变得无法忍耐了,跟踪程序线程使用,CMS GC 线程CPU 使用在初始化时都 11-99% 之间,严重影响业务处理。通过 jstat 观察,FullGC 不多,但是 YoungGC 非常频繁,YoungGC 多不影响服务性能吗?也影响。计算一个服务GC的好坏,不是看 FullGC 多少,而是看整体服务的吞吐量。
12345678910111213 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT68096.0 68096.0 16840.1 0.0 545344.0 115481.1 6658496.0 4835834.6 63280.0 60712.9 708 ...
server和client模式的区别
这两个相反的,由jvm启动时自动选择。
-server 模式:初始空间大,默认启动并行 VM,启动慢,运行快-client 模式:初始空间小,默认启动串行 VM,启动快,运行慢
一般情况下 -server 模式多
64位系统只能使用 server 模式
1234java -versionjava version "11.0.2" 2019-01-15 LTSJava(TM) SE Runtime Environment 18.9 (build 11.0.2+9-LTS)Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.2+9-LTS, mixed mode)
32位了解即可
测试 java -D 命令 -D 后面传入的命令,会解析成 System 中的属性12345678910public static void main(String[] args) { //java -DtestJvm=test TestGetSystemProperties String test = Sys ...
JVM 日志输出参数 [-XX:+PrintGCDetails] 解释
PrintGCDetails 参数
-XX:+PrintGCDetails 是在启动 java 时,添加的 VM 参数,用来在控制台中输出 GC 的详情。用这个参数可以详细的查看 GC 的回收操作,一般会将 GC 的输出,单独单到一个 log 文件当中进行查看。
添加启动参数
java -XX:+PrintGCDetails -jar Demo.jar
GC日志示例120.098: [GC (Allocation Failure) [PSYoungGen: 1022K->490K(1536K)] 1022K->522K(30208K), 0.0007804 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]1.959: [Full GC (Ergonomics) [PSYoungGen: 384K->0K(1536K)] [ParOldGen: 28064K->11941K(28672K)] 28448K->11941K(30208K), [Metaspace: 3382K->3382K(10567 ...
jstat统计JVM信息
重要参数是要看 FGC 执行了多少次。
JVM Statistics Monitoring Tool用于监控虚拟机各种运行状态信息的命令行工具,查看虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
统计垃圾回收堆的行为
jstat -gc pid
显示格式:
列说明
123456789101112131415S0C: survivor0区的总容量S1C: survivor1区的总容量S0U: survivor0区已使用的容量S1U: survivor1区已使用的容量EC: Eden区的总容量EU: Eden区已使用的容量OC: Old区的总容量OU: Old区已使用的容量PC: 当前perm的容量 (KB)PU: perm的使用 (KB)YGC: 新生代垃圾回收次数YGCT: 新生代垃圾回收时间FGC: 老年代垃圾回收次数FGCT: 老年代垃圾回收时间GCT: 垃圾回收总消耗时间
单位时间内显示次数
jstat -gc pid 秒 次数这个命令意思就是每隔2000ms输出gc情况,一共输出20次。
新生代收集器 Parallel Scavenge
新生代,多线程,使用复制算法,是多线程的并行的收集器。目标:达到一个可控的**吞吐量(Throughput)**。吞吐量:CPU用于运行代码时间 与 CPU总消耗时间的 比公式: 吞吐量 = 运行代码时间 / ( 运行代码时间 + GC时间)虚拟机运行 100 分钟,GC用掉1分钟,则吞吐量为99%。 100 /(100 + 1) = 0.99
停顿时间越短越好-XX:MaxGCPauseMillis: 最大GC停顿时间,最小可为0-XX:GCTimeRatio: 吞吐量大小,1-100
停顿时间与空间成反比停顿时间越短,则新生代的空间就越小。通过减小新生代的空间,让里面的垃圾变少,从而加快了集速度。原来:500MB 垃圾,10秒收集一次,每次停顿100毫秒为了缩短时间,修改** -XX:MaxGCPauseMillis** 参数,使新生代空间变小,产生的垃圾就少了,停顿时间短了:现在:300MB 垃圾,5秒收集一次, 每次停顿70毫秒。
那时问题来了,停顿时间下降了,但是频率高了,则吞吐量也跟着降下来了。
GC 时间占总时间的比例GCTimeRatio 进行这个设置1-100 ...
java 解决JDK内置工具不能使用问题
问题在服务器上准备排查服务进程问题,想使用jstat和jcmd这些工具,然后发现给我报了个错:
bash: jstat: command not found
这是什么鬼,程序正常跑着,难道JDK还有阉割版?看看版本,这个很正常。
123java version "1.8.0_291"Java(TM) SE Runtime Environment (build 1.8.0_291-b10)Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)
那去看看bin下面是不是把这些工具全删了:
1echo $JAVA_HOME
结果没有 JAVA_HOME 路径,这难道又是从/usr/bin指过去的,怎么总是喜欢这么玩。
1which java
结果,还真的是
/bin/java
那再看看这个java是指向哪里的:执行命令
1ll /bin/java
显示路径是:
/bin/java -> /etc/alternatives/java
那么也就是指向了 /etc/alterna ...
对象的创建
这里指普通 Java 对象,而非数组 和 Class对象等。
1.创建对象的过程new ---> 到常量池中检查是否存在一个类的符号引用 ---> 如果有,检查这个符号引用代表的类是否已被加载、解析、初始化 ---> 没有,则执行类加载过程。
2.分配对象类加载完毕后,为新生对象分配内存。对象所需内存大小在类加载完成后便完全确定。分配空间。即,从JVM堆中划出一块确定大小的内存空间。
3.分配方法有两种分配方法:
指针碰撞:使用这种方式的前提是,内存是规整的。左边是空闲的空间,右边是已使用的内存空间,用一块,就往左边移一块,就像秤砣在称中间移动一样。
空闲列表内存不规整,此时不能使用指针碰撞。JVM 就需要维护一个列表,记录哪些空间可用并给对象。
堆内存是否规整决定了使用哪种分配方法。而堆是否会规整则由GC是否带有压缩整理功能决定。
4.避免并发操作同一片内存的问题并发时,A线程 拿着指针在为对象分配 0x111111 这片空间,分配动作执行到一半,B线程 也进来了拿着同一个指针在同一个地址上分配空间。这就出现了问题。
解决方案
CAS 配置失败重试的方式保证更 ...
Java 堆内存简介
Java 堆 是虚拟机管理的最大的一块内存。是被所有线程所共享的一块内存区域,在虚拟机启动时创建。
分配内存方式所有的实例和数组都在要堆上分配,但是随着JIT编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会导至一些变化,所有的对象都分配在堆上也变得不那么绝对。
Java 堆是垃圾收集器管理的主要区域,也叫CG堆。由于现在收集器基本都爱用分代收集算法,所以Java堆中还可以细分为:新生代 和 老年代。再细致一点的有: Eden 空间、From Survivor 空间、To Survivor 空间等。从内存分配的角度来看,线程共享的Java堆中可能划多个线程私有的分配缓存区。
如何划分与存放内容无关,无论哪个区域,存储的都仍然是对象实例。进一步划分的目的是为了更好的回收内存、或都更快的分配内存。
存放特点Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像磁盘空间。堆的实现,即可固定大小,也可以扩展,通过 -Xms 和 -Xmx 控制。如果堆中没有内存实例分配,并助理堆无法再扩展时,抛出 OutOfMemoryError