1、JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
2、HotSpot参数分类
标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
试验用程序:
import java.util.List;
import java.util.LinkedList;
public class HelloGC {
public static void main(String[] args) {
System.out.println("HelloGC!");
List list = new LinkedList();
for(;;) {
byte[] b = new byte[1024*1024];
list.add(b);
}
}
}
区分概念:内存泄漏memory leak,内存溢出out of memory
java -XX:+PrintCommandLineFlags HelloGC
java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC HelloGCPrintGCDetails PrintGCTimeStamps PrintGCCauses
java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC
java -XX:+PrintFlagsInitial 默认参数值
java -XX:+PrintFlagsFinal 最终参数值
java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数
java -XX:+PrintFlagsFinal -version |grep GC
-XX:+UseSerialGC = Serial New (DefNew) + Serial Old
小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和JDK版本自动选择收集器
-XX:+UseParNewGC = ParNew + SerialOld
这个组合已经很少用(在某些版本中已经废弃)
https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future
-XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old
-XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-XX:+UseG1GC = G1
Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC
Linux下1.8版本默认的垃圾回收器到底是什么?
-Xmn -Xms -Xmx -Xss年轻代 最小堆 最大堆 栈空间
-XX:+UseTLAB使用TLAB,默认打开
-XX:+PrintTLAB打印TLAB的使用情况
-XX:TLABSize设置TLAB大小
-XX:+DisableExplictGCSystem.gc()不管用 ,FGC
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationConcurrentTime (低)打印应用程序时间
-XX:+PrintGCApplicationStoppedTime (低)打印暂停时长
-XX:+PrintReferenceGC (重要性低)记录回收了多少种不同引用类型的引用
-verbose:class类加载详细过程
-XX:+PrintVMOptions
-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial必须会用
-Xloggc:opt/log/gc.log
-XX:MaxTenuringThreshold升代年龄,最大值15
锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 … 这些不建议设置
-XX:SurvivorRatio
-XX:PreTenureSizeThreshold大对象到底多大
-XX:MaxTenuringThreshold
-XX:+ParallelGCThreads并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
-XX:+UseAdaptiveSizePolicy自动选择各区大小比例
-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreadsCMS线程数量
-XX:CMSInitiatingOccupancyFraction使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
-XX:+UseCMSCompactAtFullCollection在FGC时进行压缩
-XX:CMSFullGCsBeforeCompaction多少次FGC之后进行压缩
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingPermOccupancyFraction达到什么比例时进行Perm回收
GCTimeRatio设置GC时间占用程序运行时间的百分比
-XX:MaxGCPauseMillis停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代
-XX:+UseG1GC
-XX:MaxGCPauseMillis建议值,G1会尝试调整Young区的块数来达到这个值
-XX:GCPauseIntervalMillis?GC的间隔时间
-XX:+G1HeapRegionSize分区大小,建议逐渐增大该值,1 2 4 8 16 32。随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长ZGC做了改进(动态区块大小)
G1NewSizePercent新生代最小比例,默认为5%
G1MaxNewSizePercent新生代最大比例,默认为60%
GCTimeRatioGC时间建议比例,G1会根据这个值调整堆空间
ConcGCThreads线程数量
InitiatingHeapOccupancyPercent启动G1的堆空间占用比例
http://www.ityouknow.com/jvm/2017/09/19/GC-tuning.html
调优,从业务场景开始,没有业务场景的调优都是耍流氓。
无监控(压力测试,能看到结果),不调优。
步骤:
1、熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
1.1、响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
1.2、吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
2、选择回收器组合。3、计算内存需求(经验值 1.5G 16G)。4、选定CPU(越高越好)5、设定年代大小、升级年龄。6、设定日志参数。6.1 -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause。6.2或者每天产生一个日志文件
7、观察日志情况。
案例1
垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?
这个问题比较业余,因为很多不同的服务器配置都能支撑(1.5G 16G)1小时360000集中时间段, 100个订单/秒,(找一小时内的高峰期,1000订单/秒)经验值,非要计算:一个订单产生需要多少内存?512K * 1000 500M内存专业一点儿问法:要求响应时间100ms压测!
案例2
12306遭遇春节大规模抢票应该如何支撑?12306应该是中国并发量最大的秒杀网站:号称并发量100W最高CDN -> LVS -> NGINX -> 业务系统 -> 每台机器1W并发(10K问题) 100台机器普通电商订单 -> 下单 ->订单系统(IO)减库存 ->等待用户付款12306的一种可能的模型: 下单 -> 减库存 和 订单(redis kafka) 同时异步进行 ->等付款减库存最后还会把压力压到一台服务器可以做分布式本地库存 + 单独服务器做库存均衡大流量的处理方法:分而治之
案例3
怎么得到一个事务会消耗多少内存?
弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到。
用压测来确定。
package com.aiz.jvm.gc;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 从数据库中读取信用数据,套用模型,并把结果进行记录和传输
*/
public class T15_FullGC_Problem01 {
private static class CardInfo {
BigDecimal price = new BigDecimal(0.0);
String name = "张三";
int age = 5;
Date birthdate = new Date();
public void m() {}
}
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
public static void main(String[] args) throws Exception {
executor.setMaximumPoolSize(50);
for (;;){
modelFit();
Thread.sleep(100);
}
}
private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
taskList.forEach(info -> {
// do something
executor.scheduleWithFixedDelay(() -> {
//do sth with info
info.m();
}, 2, 3, TimeUnit.SECONDS);
});
}
private static List<CardInfo> getAllCardInfo(){
List<CardInfo> taskList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
CardInfo ci = new CardInfo();
taskList.add(ci);
}
return taskList;
}
}
1、程序启动加入参数:
java -Djava.rmi.server.hostname=192.168.17.11
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=11111
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false XXX
2、如果遭遇 Local host name unknown:XXX的错误,修改/etc/hosts文件,把XXX加入进去
192.168.17.11 basic localhost localhost.localdomain localhost4
localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
3、关闭linux防火墙(实战中应该打开对应端口)
service iptables stop
chkconfig iptables off #永久关闭
4、windows上打开 jconsole远程连接 192.168.17.11:11111
https://www.cnblogs.com/liugh/p/7620336.html (简单做法)
OOM产生的原因多种多样,有些程序未必产生OOM,不断FGC(CPU飙高,但内存回收特别少) (上面案例)
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\lib\idea_rt.jar=49316:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\work\ijprojects\JVM\out\production\JVM;C:\work\ijprojects\ObjectSize\out\artifacts\ObjectSize_jar\ObjectSize.jar" com.mashibing.jvm.gc.LambdaGC
[GC (Metadata GC Threshold) [PSYoungGen: 11341K->1880K(38400K)] 11341K->1888K(125952K), 0.0022190 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Metadata GC Threshold) [PSYoungGen: 1880K->0K(38400K)] [ParOldGen: 8K->1777K(35328K)] 1888K->1777K(73728K), [Metaspace: 8164K->8164K(1056768K)], 0.0100681 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
[GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] 1777K->1777K(73728K), 0.0005698 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] [ParOldGen: 1777K->1629K(67584K)] 1777K->1629K(105984K), [Metaspace: 8164K->8156K(1056768K)], 0.0124299 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:388)
at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:411)
Caused by: java.lang.OutOfMemoryError: Compressed class space
at sun.misc.Unsafe.defineClass(Native Method)
at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:63)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
at sun.reflect.MethodAccessorGenerator.generateSerializationConstructor(MethodAccessorGenerator.java:112)
at sun.reflect.ReflectionFactory.generateConstructor(ReflectionFactory.java:398)
at sun.reflect.ReflectionFactory.newConstructorForSerialization(ReflectionFactory.java:360)
at java.io.ObjectStreamClass.getSerializableConstructor(ObjectStreamClass.java:1574)
at java.io.ObjectStreamClass.access$1500(ObjectStreamClass.java:79)
at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:519)
at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:494)
at java.security.AccessController.doPrivileged(Native Method)
at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:494)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:391)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1134)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at javax.management.remote.rmi.RMIConnectorServer.encodeJRMPStub(RMIConnectorServer.java:727)
at javax.management.remote.rmi.RMIConnectorServer.encodeStub(RMIConnectorServer.java:719)
at javax.management.remote.rmi.RMIConnectorServer.encodeStubInAddress(RMIConnectorServer.java:690)
at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:439)
at sun.management.jmxremote.ConnectorBootstrap.startLocalConnectorServer(ConnectorBootstrap.java:550)
at sun.management.Agent.startLocalManagementAgent(Agent.java:137)
Object o = null;
for(int i=0; i<100; i++) {
o = new Object();
//业务处理
}
for(int i=0; i<100; i++) {
Object o = new Object();
}