目的是减少开销很大的系统资源的创建和销毁,比如数据库连接,网络通信连接,线程资源 等等。类似单例模式、池化技术都可以
3.4.4 JVM
与 JIT 编译器相关的优化
选择编译器是运行 java 程序首先要做的选择之一
热点编译的概念
对于程序来说,通常只有一部分代码被经常执行,这些关键代码被称为应用的热点,执行的越多就认为是越热。将这些代码编译为本地机器特定的二进制码,可以有效提高应用性能。
选择编译器类型
-server
更晚编译,但是编译后的优化更多,性能更高
-client:
很早就开始编译
-XX:+TieredCompilation:
开启分层编译,可以让 jvm 在启动时启用 client 编译,随着代码变热后再转为 server 编译。
缺省编译器取决于机器位数、操作系统和 CPU 数目。32 位的机器上,一般默认都是 client
编译,64 位机器上一般都是 server 编译,多核机器一般是 server 编译。
-Xint
表示禁用 JIT,所有字节码都被解释执行,这个模式的速度最慢的。
-Xcomp
表示所有字节码都首先被编译成本地代码,然后再执行。
-Xmixed
默认模式,让 JIT 根据程序运行的情况,有选择地将某些代码编译成本地代码。
-Xcomp 和-Xmixed
到底谁的速度快,针对不同的程序可能有不同的结果,基本还是推荐用默认模式。
代码缓存相关
在编译后,会有一个代码缓存保存编译后的代码,一旦这个缓存满了,jvm 将无法继续编译代码。
当 jvm 提示: CodeCache is full,就表示需要增加代码缓存大小。
–XX:ReservedCodeCacheSize=N 可以用来调整这个大小。
编译阈值
代码是否进行编译,取决于代码执行的频度,是否到达编译阈值。 计数器有两种:方法调用计数器和方法里的循环回边计数器
一个方法是否达到编译阈值取决于方法中的两种计数器之和。编译阈值调整的参数为:
#-XX:CompileThreshold=N
这个地方看一下了解一下就好,据我所知很少有会问到这一步的
方法调用计数器
统计的并不是方法被调用的绝对次数,而是一个相对的执行频率,即一段时间之内方法被调用的次数。当超过一定的时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器热度的衰减(Counter Decay),而这段时间就称为此方法统计的半衰周期(Counter Half Life Time)。进行热度衰减的动作是在虚拟机进行垃圾收集时顺便进行的,可以使用虚拟机参数-XX:-UseCounterDecay 来关闭热度衰减,让方法计数器统计方法调用的绝对次数, 这样,只要系统运行时间足够长,绝大部分方法都会被编译成本地代码。另外,可以使用-XX: CounterHalfLifeTime 参数设置半衰周期的时间,单位是秒。
回边计数器没有计数热度衰减的过程,因此这个计数器统计的就是该方 法循环执行的绝对次数。
编译线程
进行代码编译的时候,是采用多线程进行编译的。
方法内联
内联默认开启,-XX:-Inline,可以关闭,但是不要关闭,一旦关闭对性能有巨大影响。 方法是否内联取决于方法有多热和方法的大小,
很热的方法如果方法字节码小于 325 字节才会内联,这个大小有参数
-XX:MaxFreqInlinesSzie=N 调整,但是这个很热与热点编译不同,没有任何参数可以调整热度。
方法小于 35 个字节码,一定会内联,这个大小可以通过参数-XX:MaxInlinesSzie=N 调整。
逃逸分析
是 JVM 所做的最激进的优化,最好不要调整相关的参数。
3.4.5 GC 调优目的
GC 的时间够小
GC 的次数够少
发生 Full GC 的周期足够的长,时间合理,最好是不发生。
调优的原则和步骤
============
1. 大多数的 java 应用不需要 GC 调优
2. 大部分需要 GC 调优的的,不是参数问题,是代码问题
3. 在实际使用中,分析 GC 情况优化代码比优化 GC 参数要多得多;
4. GC 调优是最后的手段
GC 调优的最重要的三个选项:
第一位:选择合适的 GC 回收器
第二位:选择合适的堆大小
第三位:选择年轻代在堆中的比重
步骤
1,监控 GC 的状态
使用各种 JVM 工具,查看当前日志,分析当前 JVM 参数设置,并且分析当前堆内存快照和
gc 日志,根据实际的各区域内存划分和 GC 执行时间,觉得是否进行优化;
2,分析结果,判断是否需要优化
如果各项参数设置合理,系统没有超时日志出现,GC 频率不高,GC 耗时不高,那么没有必要进行 GC 优化;如果 GC 时间超过 1-3 秒,或者频繁 GC,则必须优化;
注:如果满足下面的指标,则一般不需要进行 GC:
Minor GC 执 行 时 见 不 到 50ms; Minor GC 执行不频繁,约 10 秒一次; Full GC 执行时间不到 1s;
Full GC 执行频率不算频繁,不低于 10 分钟 1 次;
3,调整 GC 类型和内存分配
如果内存分配过大或过小,或者采用的 GC 收集器比较慢,则应该优先调整这些参数,并且先找 1 台或几台机器进行 beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择;
4,不断的分析和调整
通过不断的试验和试错,分析并找到最合适的参数
5,全面应用参数
如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪。
学会阅读 GC 日志
//以参数-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+UseSerialGC 为例:
[DefNew: 1855K->1855K(1856K), 0.0000148 secs][Tenured: 2815K->4095K(4096K), 0.0134819 secs] 4671K
DefNew 指明了收集器类型,而且说明了收集发生在新生代。
1855K->1855K(1856K)表示,回收前 新生代占用 1855K,回收后占用 1855K,新生代大小
1856K。
0.0000148 secs 表明新生代回收耗时。
Tenured 表明收集发生在老年代
2815K->4095K(4096K), 0.0134819 secs:含义同新生代
最后的 4671K 指明堆的大小。
收集器参数变为-XX:+UseParNewGC,日志变为:
[ParNew: 1856K->1856K(1856K), 0.0000107 secs][Tenured: 2890K->4095K(4096K), 0.0121148 secs]
收集器参数变为-XX:+ UseParallelGC 或 UseParallelOldGC,日志变为: [PSYoungGen: 1024K->1022K(1536K)] [ParOldGen: 3783K->3782K(4096K)] 4807K->4804K(5632K),
CMS 收集器和 G1 收集器会有明显的相关字样
其他与 GC 相关的参数
#调试跟踪之 打印简单的 GC 信息 参数: -verbose:gc, -XX:+PrintGC
#打印详细的 GC 信息 -XX:+PrintGCDetails, +XX:+PrintGCTimeStamps
#-Xlogger:logpath 设置 gc 的日志库,
如: -Xlogger:log/gc.log, 将 gc.log 的路径设置到当前目录的 log 目录下.
应用场景: 将 gc 的日志独立写入日志文件,将 GC 日志与系统业务日志进行了分离,方便开发人员进行追踪分析。
#-XX:+PrintHeapAtGC, 打印推信息
参数设置: -XX:+PrintHeapAtGC
应用场景: 获取 Heap 在每次垃圾回收前后的使用状况
#-XX:+TraceClassLoading
参数方法: -XX:+TraceClassLoading
应用场景: 在系统控制台信息中看到 class 加载的过程和具体的 class 信息,可用以分析类的加载顺序以及是否可进行精简操作。
#-XX:+DisableExplicitGC 禁止在运行期显式地调用 System.gc()
#-XX:-HeapDumpOnOutOfMemoryError 默认关闭,建议开启,在java.lang.OutOfMemoryError 异常出现时,输出一个 dump.core 文件,记录当时的堆内存快照。
#-XX:HeapDumpPath=./java_pid.hprof 默认是 java 进程启动位置,用来设置堆内存快照的存储文件路径。
推荐策略
年轻代大小选择
· 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择). 在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
· 吞吐量优先的应用:尽可能的设置大,可能到达 Gbit 的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合 8CPU 以上的应用.
· 避免设置过小.当新生代设置过小时会导致:1.YGC 次数更加频繁 2.可能导致 YGC 对象直接进入旧生代,如果此时旧生代满了,会触发 FGC.
年老代大小选择
响应时间优先的应用:
年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:
并发垃圾收集信息、持久代并发收集次数、传统 GC 信息、花在年轻代和年老代回收上的时间比例。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对 象
3.4.6 调优实战不同的内存大小
不同的 GC 回收器
==============
3.4.7 存储性能优化
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
总结
对于面试,一定要有良好的心态,这位小伙伴面试美团的时候没有被前面阿里的面试影响到,发挥也很正常,也就能顺利拿下美团的offer。
小编还整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家,
最后感谢大家的支持,希望小编整理的资料能够帮助到大家!也祝愿大家都能够升职加薪!
3-1711057739154)]
[外链图片转存中…(img-IQ75Uxy7-1711057739155)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-Sn41lroW-1711057739155)]
总结
对于面试,一定要有良好的心态,这位小伙伴面试美团的时候没有被前面阿里的面试影响到,发挥也很正常,也就能顺利拿下美团的offer。
小编还整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家,
[外链图片转存中…(img-oe03b6yK-1711057739156)]
[外链图片转存中…(img-O40OzdIP-1711057739156)]
最后感谢大家的支持,希望小编整理的资料能够帮助到大家!也祝愿大家都能够升职加薪!