本文目录一览:
- 1、jvm调优如何做?
- 2、JDK8、9、10的区别
- 3、6个重要的JVM性能参数
- 4、JDK1.8中,默认的Metaspace大小是多少
- 5、有人懂JVM调优吗
- 6、java系统怎么做性能测试调优?是不是掌握了jvm就差不多了?
jvm调优如何做?
Jvm调优依次参考如下
如果没有必要,请不要做调优
如果没有必要,请不要做调优。没有万能的调优,只有根据使用场景选择合适的手段,初始默认指定堆大小,元空间大小(jdk8)即可
确认性能问题由JVM再考虑调优,如fullGC频繁,GC时间较长,内存使用不正常,OOM等。开启JVM监控,记录GC日志,分析GC情况
JVM调优的目标是减少/避免老年代GC
对于追求响应时间的如web系统使用并发垃圾回收器(jdk8开启G1,低版本使用CMS)
根据JVM内存使用情况,可以考虑手动设置年轻代大小,survivor区大小,减少/避免垃圾进入老年代(注意jdk8默认开启自适应调节,需关闭)
影响GC时间的还有GC线程数等等,需要结合GC日志分析GC过程可能存在的问题
JDK8、9、10的区别
JDK8、9、10的区别为:模式不同、引入不同、概念不同。
一、模式不同
1、JDK8:JDK8的部署是一个单体模式,即使项目内容少,也需要一整套的JRE环境。
2、JDK9:JDK9引入模块后,能将所有的类组织成模块形式。在新建项目时,不再需要整套的JRE环境。
3、JDK8:JDK10能将所有的类组织成模块形式。在新建项目时,不再需要整套的JRE环境。
二、引入不同
1、JDK8:JDK8在接口中不能引入默认方法和静态方法,只能在类中引入默认方法和静态方法。
2、JDK9:JDK9在接口中不能引入默认方法和静态方法,只能在类中引入默认方法和静态方法。
3、JDK8:JDK10既能在类中引入默认方法和静态方法,也能在接口中能引入默认方法和静态方法。
三、概念不同
1、JDK8:JDK8引入了Lambda 表达式概念。
2、JDK9:JDK9在Lambda 表达式的基础上,引入了Reactive Streams(响应式流)概念。
3、JDK8:JDK10在Reactive Streams(响应式流)的基础上,引入了订阅管理器连接订阅者和发布者概念。
6个重要的JVM性能参数
围绕垃圾收集和内存,您可以将600多个参数传递给 JVM 。如果包括其他方面,则JVM参数总数将很容易超过1000+。任何人都无法消化和理解太多的论据。在本文中,重点介绍了七个重要的 JVM 参数,在 Java性能测试 中起着非常重要的作用。
-Xmx 可能是最重要的 JVM 参数。 -Xmx 定义要分配给应用程序的最大堆大小。。您可以这样定义应用程序的堆大小: -Xmx2g 。
堆大小在影响应用性能和所需物理硬件需求。这带来了一个问题,我的应用程序正确的堆大小是多少?我应该为应用程序分配大堆大小还是小堆大小?答案是:取决于需求和预算。
将 -Xms 和 -Xmx 设置为相同值的会提高JVM性能
元空间是将存储 JVM 的元数据定义(例如类定义,方法定义)的区域。默认情况下,可用于存储此元数据信息的内存量是无限的(即受您的容器或计算机的RAM大小的限制)。您需要使用 -XX:MaxMetaspaceSize 参数来指定可用于存储元数据信息的内存量的上限。
-XX:MaxMetaspaceSize=256m
OpenJDK中有7种不同的GC算法:
如果您未明确指定GC算法,那么JVM将选择默认算法。在Java 8之前, Parallel GC 是默认的GC算法。从Java 9开始, G1 GC 是默认的GC算法。
GC算法的选择对于确定应用程序的性能起着至关重要的作用。根据我们的研究,我们正在使用Z GC算法观察到出色的性能结果。如果使用 JVM 11+ ,则可以考虑使用 Z GC 算法(即 -XX:+ UseZGC )。
下表总结了激活每种垃圾收集算法所需传递的JVM参数。
垃圾收集日志包含有关垃圾收集事件,回收的内存,暂停时间段等信息,可以通过传递以下JVM参数来启用垃圾收集日志:
从JDK 1到JDK 8:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:{file-path}
从JDK 9及更高版本开始:
-Xlog:gc*:file={file-path}
Demo:
通常,GC日志用于调整垃圾回收性能。但是,GC日志包含重要的微观指标。这些指标可用于预测应用程序的可用性和性能特征。在本文中将重点介绍一种这样的标尺:GC吞吐量。GC吞吐量是您的应用程序在处理客户交易中花费的时间与它在处理GC活动中花费的时间之比。假设您的应用程序的GC吞吐量为98%,则意味着应用程序将其98%的时间用于处理客户活动,其余2%用于GC活动。
现在,让我们看一个健康的JVM的堆使用情况图:
您会看到一个完美的锯齿图案。您会注意到,当运行Full GC(红色三角形)时,内存利用率将一直下降到最低。
现在,让我们看一下有问题的JVM的堆使用情况图:
您可以注意到,在图表的右端,即使GC反复运行,内存利用率也没有下降。这是一个典型的内存泄漏迹象,表明该应用程序正在存在某种内存问题。
如果您仔细观察一下该图,您会发现重复的完整GC开始在上午8点左右开始。但是,该应用程序仅在上午8:45左右开始获取OutOfMemoryError。到上午8点,该应用程序的GC吞吐量约为99%。但是,在上午8点之后,GC吞吐量开始下降到60%。因为当重复的GC运行时,该应用程序将不会处理任何客户交易,而只会进行GC活动。
OutOfMemoryError 是一个严重的问题,它将影响您的应用程序的可用性和性能。要诊断 OutOfMemoryError 或任何与内存相关的问题,必须在应用程序开始遇到 OutOfMemoryError 的那一刻或一瞬间捕获堆转储。由于我们不知道何时会抛出 OutOfMemoryError ,因此很难在抛出时左右的正确时间手动捕获堆转储。但是,可以通过传递以下JVM参数来自动化捕获堆转储:
-XX:+ HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath = {HEAP-DUMP-FILE-PATH}
在 -XX:HeapDumpPath 中,需要指定堆转储所在的文件路径。传递这两个JVM参数时,将在抛出 OutOfMemoryError 时自动捕获堆转储并将其写入定义的文件路径。例:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof
一旦捕获了堆转储,就可以使用 HeapHero 和 EclipseMAT 之类的工具来分析堆转储。
每个应用程序将具有数十,数百,数千个线程。每个线程都有自己的堆栈。在每个线程的堆栈中,存储以下信息:
他们每个都消耗内存。如果它们的使用量超出某个限制,则会引发 StackOverflowError 。可以通过传递-Xss参数来增加线程的堆栈大小限制。例:
-Xss256k
如果将此 -Xss 值设置为一个很大的数字,则内存将被阻塞并浪费。假设您将 -Xss 值指定为 2mb ,而只需要 256kb ,那么您将浪费大量的内存。
假设您的应用程序有500个进程,然后 -Xss 值为 2Mb ,则您的线程将消耗 1000Mb 的内存。另一方面,如果您仅将 -Xss 分配为 256kb ,那么您的线程将仅消耗 125Mb 的内存。每个JVM将节省 875Mb 内存。
注意:线程是在堆(即 -Xmx )之外创建的,因此这 1000Mb 将是您已经分配的-Xmx值的补充。
现代应用程序使用多种协议(即SOAP,REST,HTTP,HTTPS,JDBC,RMI)与远程应用程序连接。有时远程应用程序可能需要很长时间才能做出响应,有时它可能根本不响应。
如果没有正确的超时设置,并且远程应用程序的响应速度不够快,则您的应用程序线程/资源将被卡住。远程应用程序无响应可能会影响您的应用程序的可用性。它可以使您的应用程序停止磨削。为了保护应用程序的高可用性,应配置适当的超时设置。
您可以在JVM级别传递这两个强大的超时网络属性,这些属性可以全局适用于所有使用 java.net.URLConnection 的协议处理程序:
sun.net.client.defaultConnectTimeout :指定建立到主机的连接的超时(以毫秒为单位)。例如,对于HTTP连接,它是与HTTP服务器建立连接时的超时。当建立与资源的连接时, sun.net.client.defaultReadTimeout 指定从输入流读取时的超时(以毫秒为单位)。
例如,如果您要将这些属性设置为2秒:
注意,默认情况下,这两个属性的值为-1,这表示未设置超时。
JDK1.8中,默认的Metaspace大小是多少
因为MetaSpace不控制就会无限增大,直到把机器内存都耗光所以启动参数里设了个MaxMetaspaceSize,但这样的后果就是tomcat重新部署几次之后还是OutOfMemory了,错误信息变成java.lang.OutOfMemoryError:Metaspace没看出来跟以前比有啥优势呀。
有人懂JVM调优吗
JVM是最好的软件工程之一,它为Java提供了坚实的基础,许多流行语言如Kotlin、Scala、Clojure、Groovy都使用JVM作为运行基础。一个专业的Java工程师必须要了解并掌握JVM,接下来就给大家分享Java基础知识中JVM调优相关知识点。
杭州Java基础知识学习之JVM调优讲解
JVM常见的调优参数包括:
-Xmx:指定java程序的最大堆内存, 使用java -Xmx5000M -version判断当前系统能分配的最大堆内存;
-Xms:指定最小堆内存, 通常设置成跟最大堆内存一样,减少GC;
-Xmn:设置年轻代大小。整个堆大小=年轻代大小+年老代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8;
-Xss:指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError);
-XX:PermSize:指定方法区(永久区)的初始值,默认是物理内存的1/64,在Java8永久区移除, 代之的是元数据区,由-XX:MetaspaceSize指定;
-XX:MaxPermSize:指定方法区的最大值, 默认是物理内存的1/4,在java8中由-XX:MaxMetaspaceSize指定元数据区的大小;
-XX:NewRatio=n:年老代与年轻代的比值,-XX:NewRatio=2, 表示年老代与年轻代的比值为2:1;
-XX:SurvivorRatio=n:Eden区与Survivor区的大小比值,-XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to)。
JVM实质上分为三大块,年轻代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消)。
年轻代大小选择
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
减少年轻代和年老代花费的时间,一般会提高应用的效率。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
较小堆引起的碎片问题
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩。
java系统怎么做性能测试调优?是不是掌握了jvm就差不多了?
JVM是最好的软件工程之一,它为Java提供了坚实的基础,许多流行语言如Kotlin、Scala、Clojure、Groovy都使用JVM作为运行基础。一个专业的Java工程师必须要了解并掌握JVM,接下来就给大家分享Java基础知识中JVM调优相关知识点。
杭州Java基础知识学习之JVM调优讲解
JVM常见的调优参数包括:
-Xmx:指定java程序的最大堆内存, 使用java -Xmx5000M -version判断当前系统能分配的最大堆内存;
-Xms:指定最小堆内存, 通常设置成跟最大堆内存一样,减少GC;
-Xmn:设置年轻代大小。整个堆大小=年轻代大小+年老代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8;
-Xss:指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError);
-XX:PermSize:指定方法区(永久区)的初始值,默认是物理内存的1/64,在Java8永久区移除, 代之的是元数据区,由-XX:MetaspaceSize指定;
-XX:MaxPermSize:指定方法区的最大值, 默认是物理内存的1/4,在java8中由-XX:MaxMetaspaceSize指定元数据区的大小;
-XX:NewRatio=n:年老代与年轻代的比值,-XX:NewRatio=2, 表示年老代与年轻代的比值为2:1;
-XX:SurvivorRatio=n:Eden区与Survivor区的大小比值,-XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to)。
JVM实质上分为三大块,年轻代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消)。
年轻代大小选择
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
减少年轻代和年老代花费的时间,一般会提高应用的效率。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
较小堆引起的碎片问题
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩。