一篇文章带你搞定JAVA内存泄漏
作者:香菜聊游戏 发布时间:2022-04-28 21:07:08
1、什么是内存泄漏
内存泄漏是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏。随着垃圾回收器活动的增加以及内存占用的不断增加,程序性能会逐渐表现出来下降,极端情况下,会引发OutOfMemoryError导致程序崩溃。
2、内存泄漏的原因
JVM 虚拟机是使用引用计数法和可达性分析来判断对象是否可回收,本质是判断一个对象是否还被引用,如果没有引用则回收。在开发的过程中,由于代码的实现不同就会出现很多种内存泄漏问题,让gc 系统误以为此对象还在引用中,无法回收,造成内存泄漏。
3、内存泄漏有哪些情况
3.1 代码中没有及时释放,导致内存无法回收。
下面的代码,因为是双向链表,但是断开的不够彻底,prev节点依然引用这当前正在使用的节点,导致无法回收
public class ListNode {
int val;
ListNode next;
ListNode prev;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next, ListNode prev) {
this.val = val;
this.next = next;
this.prev = prev;
}
public static void main(String[] args) {
ListNode curr = new ListNode(1);
ListNode prev = new ListNode(2);
ListNode next = new ListNode(3);
curr.prev = prev;
curr.next = next;
curr.prev = null;
}
}
public static void main(String[] args) {
ListNode curr = new ListNode(1);
ListNode prev = new ListNode(2);
ListNode next = new ListNode(3);
curr.prev = prev;
curr.next = next;
curr.prev = null;
}
}
3.2 资源未关闭造成的内存泄漏
各种连接,如数据库连接、网络连接和IO连接等,文件读写等,可以使用 try-with-resources 读取完文件,自动资源释放
try (RandomAccessFile raf = new RandomAccessFile(filePath, "r");) {
Image image = null;
while((image = parseImage(raf)) != null){
imageList.add(image);
}
return imageList;
} catch(Exception e){
log.error("parse file error, path: {},", path, e);
return null;
}
3.3 全局缓存持有的对象不使用的时候没有及时移除,导致一直在内存中无法移除
3.4 静态集合类
如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。生命周期长的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。
3.5 堆外内存无法回收
堆外内存不受gc的管理,可能因为第三方的bug出现内存泄漏
4、内存泄漏的解决办法
1.尽量减少使用静态变量,或者使用完及时 赋值为 null。
2.明确内存对象的有效作用域,尽量缩小对象的作用域,能用局部变量处理的不用成员变量,因为局部变量弹栈会自动回收;
3.减少长生命周期的对象持有短生命周期的引用;
4.使用StringBuilder和StringBuffer进行字符串连接,Sting和StringBuilder以及StringBuffer等都可以代表字符串,其中String字符串代表的是不可变的字符串,后两者表示可变的字符串。如果使用多个String对象进行字符串连接运算,在运行时可能产生大量临时字符串,这些字符串会保存在内存中从而导致程序性能下降。
5.对于不需要使用的对象手动设置null值,不管GC何时会开始清理,我们都应及时的将无用的对象标记为可被清理的对象;
6.各种连接(数据库连接,网络连接,IO连接)操作,务必显示调用close关闭。
5、内存问题排查
没有任何一个程序员想要出现这种问题,但是出现了问题也要解决,内存泄漏的主要表象就是内存不足,内存告警之后如何判断是否有内存泄漏。
第一步 首先确认逻辑问题
查看内存中对象的数量和大小,判断是否在合理的范围,如果在合理的范围内,增大内存配置,调整内存比例就可以了。
命令:
jmap -heap pid
第二步:分析gc是否正常执行
命令:
jstat -gcutil <pid> 1000
S0 — Heap上的 Survivor space 0 区已使用空间的百分比
S1 — Heap上的 Survivor space 1 区已使用空间的百分比
E — Heap上的 Eden space 区已使用空间的百分比
O — Heap上的 Old space 区已使用空间的百分比
P — Perm space 区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)
LGCC - 进行GC的原因(低版本jdk可能没有这一列)
从这里观察gc是否异常,也可以根据这个进行jvm内存分配调优,来提高性能降低gc对性能的损耗
第三步 确认下版本新增代码的改动,尽快从代码上找出问题。
第四步:开启各种命令行和 导出 dump 各种工具分析
-XX:+HeapDumpOnOutOfMemoryError
-XX:OnError
-XX:+ShowMessageBoxOnError
推荐使用jprofile 进行本地分析,可以不用记住那么多命令。
总结:
现在的服务器内存虽然很大,但是且用且珍惜,不要等到出现问题了才知道后果,在开发中规范自己代码,用完的对象及时释放,减少垃圾对象。出现问题了也不要慌,仔细分析代码,一切都是有原因的。
本篇文章就到这里了,希望能给你带来帮助,也希望您能多多关注脚本之家的更多内容!
来源:https://gamwatcher.blog.csdn.net/article/details/116201538
猜你喜欢
- 效果如下:鄙人虽然开发WPF有些时间,但之前一直是一些简单Template和Style改改之类的工作,并没有深入研究过。此次为了完成工作,首
- //截取全屏图象 private void btnFul
- 1. 三种常用的字符串判空串方法:Length法:bool isEmpty = (str.Length == 0);Empty法:bool
- 字符串采用unicode编码的方式时,计算字符串长度的方法找出UNICODE编码中的汉字的代表的范围“\u4E00” 到“\u9FBB”之间
- 前言在 C# 项目中通过链接方式引入文件可以让我们在项目中使用这些文件中的代码。常见的比如链接 AssemblyInfo.cs 文件,这样我
- 网页爬虫:其实就是一个程序用于在互联网中获取符合指定规则的数据。package day05; import java.io.Buffered
- JDK 1.5开始提供ScheduledThreadPoolExecutor类,ScheduledThreadPoolExecutor类继承
- 近几年移动互联网的高速发展,智能手机的使用用户呈现 * 性增长,手机终端上的App 种类繁多,大多数App 都需要与后台系统进行交互,交互的第
- 先看英文意思命名空间using System.Text.RegularExpressions;正则表达式是干什么用的?简单来说就是 检索 数
- public static void main(String[] args) { System.out
- 本文实例讲述了C#中static静态变量的用法。分享给大家供大家参考。具体如下:使用 static 修饰符声明属于类型本身而不是属于特定对象
- 首先我先声明一点,本文单纯就是技术探讨,要从实际应用中来说的话,我并不建议这样去玩分布式事务、也不建议这样去玩多数据源,毕竟分布式事务主要还
- 前言 之前的文章有介绍ActivityGroup,不少人问嵌套使用的问题,同样的需求在Fragment中也存在,幸好在最新的An
- start方法和run方法$start()$方法用来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到$cpu$时间片,就
- 使用AOP的原因(AOP简介)我们知道,spring两大核心,IOC(控制反转)和AOP(切面),那为什么要使用AOP,AOP是什么呢,严格
- 简要:EigenFace是基于PCA降维的人脸识别算法,PCA是使整体数据降维后的方差最大,没有考虑降维后类间的变化。 它是将图像
- 本文实例为大家分享了Android下载进度监听和通知的具体代码,供大家参考,具体内容如下下载管理器关于下载进度的监听,这个比较简单,以apk
- WPF 窗体设置亚克力效果框架使用大于等于.NET40。Visual Studio 2022。项目使用 MIT 开源许可
- 问题注意:本人使用的Spring Boot 2.0.2, 对1.5.x系列未必有用。官方文档在这里直接解决办法0, 移除spring-boo
- 访问静态资源遇到的坑及解决开始是以这种结构进行的,结果页面上一篇红,访问的页面是这样的最终找出来问题,虽然每次调整路径都不对,最终查看多种方