| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> JVM性能优化,拿来吧你! -> 正文阅读 |
|
[Java知识库]JVM性能优化,拿来吧你! |
背景我们都知道 JVM 分为了新生代和老年代,并且我们在启动应用的时候都会配置对应的参数,为应用程序运行的 JVM 调整内存大小。但我们都知道,很多时候我们都只是大致估计一个数,随便填填,然后就上线了。 作者所在的公司同样存在这种情况,JVM 内存大小基本上都设得挺大的,毕竟内存大总比内存溢出好,因此就造成了不少的内存浪费。所以作者收到的任务就是对所有的应用进行一次排查,调整合适的内存参数,优化 JVM 的性能。 调优实战要对应用进行 JVM 性能调优,那么首先得知道其运行的情况。这就像去医院看医生,去开药之前需要医生先望闻问切一样。在 Java 中,有很多方式可以观察到 JVM 的内部情况,例如 JDK 提供的各种命令工作。作者所在公司使用的是 Prometheus 进行监控,因此我们可以直接在 Prometheus 上看到应用的 JVM 运行情况。 例如对于接口类型的系统来说,很多请求都是 1 秒中之内就结束。对于这种类型的请求,他们进入应用时会分配内存,结束时内存就会立刻被回收,留存下来的对象很少。这种应用的 JVM 内存情况大概是这样的:新生代消耗比较大,并且随着周期性回收内存,但老年代的内存消耗则更小。对于那些持续性处理的应用,例如持续时间长的应用处理。因为其存活时间较久,所以可能会有更多的对象晋升到老年代,因此老年代的内存消耗就比较大。 通过观察 JVM 年轻代与老年代的内存消耗情况,再结合应用本身的特性,我们可以发现应用中不合理的地方,再对应用进行针对性的优化。例如:应用某个地方每次都会存储大量的临时数据到内容中,这样就造成了 JVM 可能爆发 GC,从而导致应用卡顿。 小总结总结一下本篇文章的调优方法: 通过观察 GC 频率和停顿时间,来进行 JVM 内存空间调整,使其达到最合理的状态。调整过程记得小步快跑,避免内存剧烈波动影响线上服务。 这其实是最为简单的一种 JVM 性能调优方式了,可以算是粗调吧。但 JVM 性能调优还有更多、更详细的参数,后续有机会我们再聊聊。 此外,通过观察 JVM 年轻代与老年代的情况,也可以帮助我们对应用进行针对性的优化,从而提升应用本身的性能。 一、内存溢出内存溢出的原因:程序在申请内存时,没有足够的空间。 1. 栈溢出方法死循环递归调用(StackOverflowError)、不断建立线程(OutOfMemoryError)。 2. 堆溢出不断创建对象,分配对象大于最大堆的大小(OutOfMemoryError)。 3. 直接内存JVM 分配的本地直接内存大小大于 JVM 的限制,可以通过-XX:MaxDirectMemorySize 来设置(不设置的话默认与堆内存最大值一样,也会出现OOM 异常)。 4. 方法区溢出一个类要被垃圾收集器回收掉,判定条件是比较苛刻的,在经常动态生产大量 Class 的应用中,CGLIb 字节码增强,动态语言,大量 JSP(JSP 第一次运行需要编译成 Java 类),基于 OSGi 的应用(同一个类,被不同的加载器加载也会设为不同的类),都可能会导致OOM。 二、内存泄露程序在申请内存后,无法释放已申请的内存空间,导致这一部分的原因主要是代码写的不合理,比如以下几种情况。 1. 长生命周期的对象持有短生命周期对象的引用例如将 ArrayList 设置为静态变量,然后不断地向ArrayList中添加对象,则 ArrayList 容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。 2. 连接未关闭如数据库连接、网络连接和 IO 连接等,只有连接被关闭后,垃圾回收器才会回收对应的对象。 3. 变量作用域不合理例如: 一个变量的定义的作用范围大于其使用范围。 4. 内部类持有外部类Java 的 非静态内部类 的这种创建方式,会隐式地持有外部类的引用,而且默认情况下这个引用是强引用,因此,如果内部类的生命周期长于外部类的生命周期,程序很容易就产生内存泄露(可以理解为:垃圾回收器会回收掉外部类的实例,但由于内部类持有外部类的引用,导致垃圾回收器不能正常工作)。 解决办法:将非静态内部类改为 静态内部类,即加上 static 修饰,例如:
5. Hash值改变在集合中,如果修改了对象中的那些参与计算哈希值的字段,会导致无法从集合中单独删除当前对象,造成内存泄露。 使用例子来说明。
四、了解MATmat是一个内存泄露的分析工具。 1. 浅堆和深堆
2. MAT的使用1、下载MAT工具:下载地址 2、内存溢出例子演示
设置参数运行后,内存溢出,程序结束,然后我们就可以用下载好的MAT来分析了,当然MAT也只是分析猜想,并不代表一定是这个原因导致内存溢出。 打开我们保存的文件目录进行分析。 五、JDK提供的一些工具
所有的工具都在jdk的安装bin目录下,比如我的在 六、GC调优1. GC调优重要参数生产环境推荐开启
调优之前开始,调优之后关闭
考虑使用
2. GC调优的原则(很重要)
调优的目的
注: 如果满足下面的指标,则一般不需要进行 GC调优
3. GC调优步骤
分析GC日志
2、-XX:+UseParNewGC
3、-XX:+UseConcMarkSweepGC 和 -XX:+UseG1GC 4. 项目启动调优开启日志分析-XX:+PrintGCDetails,启动项目时,通过分析日志,不断地调整参数,减少GC次数。 例如:
5. 项目运行GC调优使用 jmeter 工具 来进行压测,然后分析原因,进行调优,当然 正式上线的项目请谨慎操作 。 jmeter工具安装使用 2、jmeter需要Java运行时环境,所以如果报错请先检查你的Java环境变量设置,解压到你想要的路径,例如我解压在 至于具体怎么使用就百度吧,基本拿到软件就知道使用了,毕竟这个说来就浪费篇幅了。 聚合报告参数 这里放出我本地 jmeter 测试一个项目之后的 聚合报告参数解释 6. 推荐策略(仅作参考)1、新生代大小选择
2、老年代大小选择 一般吞吐量优先的应用都有一个很大的新生代和一个较小的老年代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而老年代尽存放长期存活对象
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/17 20:40:59- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |