1.打印和查找上一篇讲到 的 参数
windows下可以使用findstr (代替grep)
2.Java代码获取JVM相关参数
可以借助java.lang.management.*:
public class JVMParameterTest {
@Test
public void TestGetResource(){
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage usage = memoryMXBean.getHeapMemoryUsage();
List myList = new ArrayList();
myList.add("Heap Memory setting:");
myList.add(usage.getInit());
myList.add(usage.getMax());
myList.add(usage.getUsed());
myList.add("Full info:");
myList.add("Heap info:");
myList.add(memoryMXBean.getHeapMemoryUsage());
myList.add("NonHeap info:");
myList.add(memoryMXBean.getNonHeapMemoryUsage());
List<String> inputArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();
System.out.println("=============java options==============");
inputArgs.forEach(item->System.out.println(item));
myList.add("==========Java System Status=========");
myList.add((int) Runtime.getRuntime().totalMemory());
myList.add((int) Runtime.getRuntime().freeMemory());
myList.add((int) Runtime.getRuntime().maxMemory());
myList.add("==========Java OS MXBean=========");
OperatingSystemMXBean osm =(OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
myList.add(osm.getFreePhysicalMemorySize());
myList.add(osm.getFreeSwapSpaceSize());
myList.add(osm.getTotalPhysicalMemorySize());
myList.add("osm.getAuth():"+osm.getArch());
myList.add("som.getAvailableProcessors():"+osm.getAvailableProcessors());
myList.add("som.getName():"+osm.getName());
myList.add("som.getCommittedVirtualMeSize():"+osm.getCommittedVirtualMemorySize());
myList.add("som.getProcessCpuTime():"+osm.getProcessCpuTime());
myList.add("osm.getVersion():"+osm.getVersion());
myList.add("====================获取虚拟机的内存使用情况===============");
MemoryMXBean mm = (MemoryMXBean) ManagementFactory.getMemoryMXBean();
myList.add("mm.getHeapMemoryUsage():"+mm.getHeapMemoryUsage());
myList.add("mm.getNonHeapMemoryUsage():"+mm.getNonHeapMemoryUsage());
myList.add("====================获取各个线程 状态===============");
ThreadMXBean tm = (ThreadMXBean) ManagementFactory.getThreadMXBean();
myList.add("tm.getThreadCount():"+tm.getThreadCount());
myList.add("tm.getPeakThreadCount():"+tm.getPeakThreadCount());
myList.add("tm.getCurrentThreadCpuTime():"+tm.getCurrentThreadCpuTime());
myList.add("tm.getDaemonThreadCount():"+tm.getDaemonThreadCount());
myList.add("tm.getCurrentThreadUserTime():"+tm.getCurrentThreadUserTime());
myList.add("====================获取编译器情况===============");
CompilationMXBean gm = (CompilationMXBean) ManagementFactory.getCompilationMXBean();
myList.add("gm.getName():"+gm.getName());
myList.add("gm.getTotalCompilationTime():"+gm.getTotalCompilationTime());
myList.add("==================== 获取 GC次数以及花费时间之类的信息 ===============");
List<GarbageCollectorMXBean> gcmList= ManagementFactory.getGarbageCollectorMXBeans();
gcmList.forEach(item->{
myList.add("getName:"+item.getName());
myList.add("getMemoryPoolNames:"+item.getMemoryPoolNames());
});
myList.add("==================== 获取 运行时 信息 ===============");
RuntimeMXBean rmb = (RuntimeMXBean) ManagementFactory.getRuntimeMXBean();
myList.add("getClassPath():"+rmb.getClassPath());
myList.add("getLibraryPath():"+rmb.getLibraryPath());
myList.add("getVmVersion():"+rmb.getVmVersion());
myList.forEach(item->System.out.println(item));
}
}
执行后的结果如下:
运行时的信息太多与复杂和多,不适合展示
3.HotSpot选项之垃圾回收收集器
3-1 吞吐量优先收集器的相关选项
有两个衡量收集器的指标:吞吐量和停顿时间
吞吐量:执行用户代码的实践占据总时间的比例
总时间:执行用户代码的时间和垃圾回收的时间
实践:二者不可同时进行,垃圾回收的时候,执行用户代码的线程必须暂停,这就导致程序暂时失去响应。
停顿时间:衡量垃圾回收时候造成的用户线程暂停的时间
实践:两个指标是有一定矛盾的,所以只能优先选择其中一个目标
实践:HotSpot中,侧重于吞吐量的是Parallel Scavenge和Parallel Old
Parallel Scavenge和Parallel Old 相关参数:
-XX:+UseParallelOldGC
表示年轻代和老年代都使用并行回收器
-XX:ParallelGCThreads=n
表示配置多少个线程来回收垃圾
实践:默认值,cpu小于8个,就是处理器个数;大于8,就是3+(5/8)*N
实践:也可以根据程序的需要去设置这个值,比如你的机器有16核,上面有4个Java程序,那么设置将这个值设置为4比较合理,因为JVM不会去探测同一机器上有多少个Java程序
-XX:UseAdaptiveSizePolicy
表示是否开启自适应策略
实践:打开后,JVM会自动调节JVM的年轻代大小,Eden,S的比例等参数
用户只需要设置期望的吞吐量(-XX:GCTimeRatio)和期望的停顿时间(
-XX:MaxGCPauseMillis),其余交给JVM去优化
注:如果CPU只有一个核,那么就不要开启并行回收器;很简单多线程会抢夺CPU资源;可以采用串行回收器(-XX:UseSerialGC)
3-2 CMS 垃圾回收收集器
ConcurrentMarkandSweep
相对于上面两个关注吞吐量,CMS侧重于系统停顿时间。
思路:
把收集器分成了不同的阶段,其中某些阶段是可以二者并行,这样就可以减少整体的系统停顿时间。
细节:
阶段划分
--初始标记 initial mark
--并发标记 concurrent merk
--重新标记 remark
--并发清理 concurrent clean
--并发重置 concurrent reset
缺点:
1.思路上可以知道,它是标记-清除收集器,运行一段时间,必然会产生内存碎片,从而导致无法找到连续空间来分配较大对象
2.运行过程中,占用一些内存,同时系统也在运行,如果系统产生对象的速度远远大于CMS清理的速度,就会导致CMS运行失败
以上两个发生其中一个,JVM就会促发FullGC,导致停顿时间更长
ConcurrentMarkandSweep相关选项
-XX:+UseConcMarkSweepGC
表示老年代开启CMS收集器,而年轻代默认使用并行收集器
-XX:ConcGCThreads
指定用多少个线程来执行CMS的并发阶段
-XX:CMSInitiatingOccupancyFraction
指老年代用掉多少内存后 开始进行垃圾回收
区别:吞吐量优先的收集器是在老生代内存用尽了才会收集
特点:CMS不可以,因为吞吐量优先的收集器会停止所有用户线程,所以不会产生新的对象,而CMS运行的时候,用户线程还是会产生新的对象,所以不能等到用光的时候才进行
实践:-XX:CMSInitiatingOccupancyFraction=75表示老生代用掉75%后开始回收垃圾。默认值是68。
-XX:ExplictGCInvokesConcurrent
实践:关闭时候,调用System.GC()会执行Full GC从而导致用户线程被暂停
开启的时候,显示触发GC的时候,还是使用CMS
-XX:DisableExplictGC
就是禁止显式调用GC
4:GC日志相关的选项
-XX:+PrintGC
等同于 -verbose:gc
表示开启简化的GC日志
分为GC部分和Full GC部分(容量变化和花费时间)
-XX:+PrintGCDetail:
在垃圾回收的时候打印内存回收日志,并且在进程退出时候输出当前内存各区域的分布情况
-XX:PrintGCTimeStamps
打印GC发生时候相对于JVM启动的时间间隔
-XX:+PrintGCDateStamps
打印GC发生的具体时间
例子:打开两个选项后
20**-**-**T**:52:**.613-0800: 3.***: [GC 1397*6K->583*9K(506***K), 0.14***00 secs]
-Xloggc:<file>
表示把GC写入文件
-XX:+PrintHeapAtGC
每一次GC的前后,都打印堆内存的情况
-XX:+TraceClassLoading
监控类的加载
-XX:+PrintGCApplicationStoppedTime
打印GC时线程的停顿时间
注意:这些和日志相关的选项是可以在JVM启动后,再开启;
这个时候需要使用jdk自带的命令 jinfo 去设置(jps)
也就是再有问题的时候开启GC日志
这样,两篇就说清楚了常见选项。
此处感谢博客园的狂风骤起