常见的内存泄漏及其解决方案
内存泄漏是Java开发中一个常见且令人头疼的问题,即使在使用垃圾回收机制的Java中,也无法完全避免内存泄漏的出现。当对象不再需要时却仍然占据着内存,导致内存使用量不断增加,最终可能导致 OutOfMemoryError
。本文将深入探讨Java中常见的内存泄漏及其解决方案,附带详细的代码示例,帮助你更好地理解和解决内存泄漏问题。
1. 常见的内存泄漏场景
- 静态集合类引起的内存泄漏
- 未关闭的IO资源
- 监听器和回调的非预期持有
- ThreadLocal引起的内存泄漏
- 自定义类加载器引起的内存泄漏
2. 静态集合类引起的内存泄漏
静态集合类(如 HashMap
, ArrayList
等)在应用程序生命周期内是静态的,如果没有适当地移除不再需要的对象,会导致这些对象无法被垃圾回收,从而引起内存泄漏。
示例代码:
import java.util.HashMap;
import java.util.Map;public class StaticCollectionLeak {private static final Map<Integer, String> cache = new HashMap<>();public void addToCache(int id, String value) {cache.put(id, value);}public static void main(String[] args) {StaticCollectionLeak leak = new StaticCollectionLeak();for (int i = 0; i < 100000; i++) {leak.addToCache(i, "value" + i);}// 内存使用量会不断增加}
}
解决方案:
确保及时移除不再需要的对象,或者使用 WeakHashMap
替代 HashMap
。
import java.util.WeakHashMap;
import java.util.Map;public class StaticCollectionSolution {private static final Map<Integer, String> cache = new WeakHashMap<>();public void addToCache(int id, String value) {cache.put(id, value);}public static void main(String[] args) {StaticCollectionSolution solution = new StaticCollectionSolution();for (int i = 0; i < 100000; i++) {solution.addToCache(i, "value" + i);}// 内存使用量不会持续增加}
}
3. 未关闭的IO资源
未关闭的 InputStream
或 OutputStream
等IO资源,会导致内存泄漏。
示例代码:
import java.io.FileInputStream;
import java.io.IOException;public class UnclosedIOLeak {public void readFile(String filePath) throws IOException {FileInputStream fis = new FileInputStream(filePath);// Do something with fis// 未关闭FileInputStream}public static void main(String[] args) {UnclosedIOLeak leak = new UnclosedIOLeak();try {leak.readFile("somefile.txt");} catch (IOException e) {e.printStackTrace();}}
}
解决方案:
使用 try-with-resources
确保IO资源被自动关闭。
import java.io.FileInputStream;
import java.io.IOException;public class ClosedIOSolution {public void readFile(String filePath) throws IOException {try (FileInputStream fis = new FileInputStream(filePath)) {// Do something with fis} // FileInputStream将在这里被自动关闭}public static void main(String[] args) {ClosedIOSolution solution = new ClosedIOSolution();try {solution.readFile("somefile.txt");} catch (IOException e) {e.printStackTrace();}}
}
4. 监听器和回调的非预期持有
注册的监听器或回调在不再需要时如果未被删除,会导致内存泄漏。
示例代码:
import java.util.ArrayList;
import java.util.List;public class ListenerLeak {private final List<Runnable> listeners = new ArrayList<>();public void registerListener(Runnable listener) {listeners.add(listener);}// 没有方法来移除监听器public static void main(String[] args) {ListenerLeak leak = new ListenerLeak();leak.registerListener(() -> System.out.println("Listener 1"));leak.registerListener(() -> System.out.println("Listener 2"));}
}
解决方案:
提供移除监听器的方法,并在不需要时及时移除。
import java.util.ArrayList;
import java.util.List;public class ListenerSolution {private final List<Runnable> listeners = new ArrayList<>();public void registerListener(Runnable listener) {listeners.add(listener);}public void unregisterListener(Runnable listener) {listeners.remove(listener);}public static void main(String[] args) {ListenerSolution solution = new ListenerSolution();Runnable listener1 = () -> System.out.println("Listener 1");Runnable listener2 = () -> System.out.println("Listener 2");solution.registerListener(listener1);solution.registerListener(listener2);// 移除监听器,避免内存泄漏solution.unregisterListener(listener1);solution.unregisterListener(listener2);}
}
5. ThreadLocal引起的内存泄漏
ThreadLocal
对象如果不及时移除,会导致内存泄漏,尤其是在使用线程池的情况下。
示例代码:
public class ThreadLocalLeak {private static final ThreadLocal<byte[]> threadLocal = ThreadLocal.withInitial(() -> new byte[1024 * 1024]);public static void main(String[] args) {threadLocal.get(); // 分配1MB内存// 未调用remove方法,导致内存泄漏}
}
解决方案:
在不需要时调用 ThreadLocal.remove()
方法移除对象。
public class ThreadLocalSolution {private static final ThreadLocal<byte[]> threadLocal = ThreadLocal.withInitial(() -> new byte[1024 * 1024]);public static void main(String[] args) {try {threadLocal.get(); // 分配1MB内存} finally {threadLocal.remove(); // 在使用后移除,避免内存泄漏}}
}
6. 自定义类加载器引起的内存泄漏
自定义类加载器如果未能正确卸载类,会导致内存泄漏。
示例代码:
public class CustomClassLoaderLeak {public static void main(String[] args) throws Exception {while (true) {CustomClassLoader loader = new CustomClassLoader();Class<?> clazz = loader.loadClass("LeakClass");Object instance = clazz.getDeclaredConstructor().newInstance();// 每次循环都会创建新的类加载器,但旧的类加载器未被释放}}static class CustomClassLoader extends ClassLoader {// 自定义类加载器实现}
}
解决方案:
确保自定义类加载器不再使用时,可以被垃圾回收器回收。
public class CustomClassLoaderSolution {public static void main(String[] args) throws Exception {while (true) {CustomClassLoader loader = new CustomClassLoader();Class<?> clazz = loader.loadClass("LeakClass");Object instance = clazz.getDeclaredConstructor().newInstance();// 使loader对象可以被回收loader = null;System.gc(); // 提示GC进行垃圾回收}}static class CustomClassLoader extends ClassLoader {// 自定义类加载器实现}
}
结论
Java中的内存泄漏虽然不如C/C++那样常见,但仍然是需要关注的问题。通过识别常见的内存泄漏场景并采取适当的解决方案,可以有效地减少和避免内存泄漏的发生。希望本文提供的示例和解决方案能够帮助你在实际开发中更好地处理内存泄漏问题。
相关文章:
常见的内存泄漏及其解决方案
内存泄漏是Java开发中一个常见且令人头疼的问题,即使在使用垃圾回收机制的Java中,也无法完全避免内存泄漏的出现。当对象不再需要时却仍然占据着内存,导致内存使用量不断增加,最终可能导致 OutOfMemoryError。本文将深入探讨Java中…...
SQLSERVER 触发器记录表某个字段更新记录
想要记录该字段的原值和现有值,触发器写法: CREATE TRIGGER tr_UpdateEmployeeDepartment ON Employees AFTER UPDATE AS BEGINSET NOCOUNT ON; -- 避免多余的计数消息IF UPDATE(Department) -- 检查是否更新了 Department 字段BEGININSERT INTO Update…...
现代前端架构介绍(第一部分):App是如何由不同的构建块构成的
远离JavaScript疲劳和框架大战,了解真正重要的东西 几周前,我的同事们对我们的前端架构、代码结构和面临的挑战很感兴趣。在做了几次关于如何构建可扩展且健壮的前端的演讲后,我觉得把它们都总结一下并与社区分享我们的策略是一个不错的主意。…...
Android 11 关于按键拦截/按键事件处理分享
系统在frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java处理按键事件,不管是物理按键还是 SystemUI的nav_bar上的虚拟按键(使用了KeyEvent类中的,比如:KeyEvent.KEYCODE_VOLUME_UP). 主要注意的有两个函数: interceptKeyBef…...
最新TomatoIDC开源虚拟主机销售系统源码/有插件系统模块+模版系统
源码简介: 最新TomatoIDC开源虚拟主机销售系统源码,它有一个方便扩展的插件和模版系统模块,使用实用。 TomatoIDC,一款遵循GPL3.0协议的开源虚拟主机销售系统,不仅有着可以轻松扩展的插件系统和模版系统,…...
简单的docker学习 第4章docker容器
第4章 Docker容器 4.1 容器基础 4.1.1 容器启动流程 通过 docker run 命令可以启动运行一个容器。该命令在执行时首先会在本地查找指定的镜像,如果找到了,则直接启动,否则会到镜像中心查找。如果镜像中心存在该镜像,则会下载到…...
PHP中如何声明数组
数组是一种数据结构,用于存储一系列的值或对象,这些值或对象可以通过索引(或键)来访问。在PHP中,数组是一种复合类型的数据结构,可以存储多个值,这些值可以是整型、字符串、布尔值,甚…...
JavaScript前端面试题——fetch
什么是fetch? fetch:fetch是浏览器内置的api,用于发送网络请求 ajax&axios&fetch的关系 ajax:ajax 是一种基于原生 JavaScript 的异步请求技术。它使用 XMLHttpRequest 对象来发送请求和接收响应。 axios:…...
在Qt中获取Windows中进程的PID
主要是用到了系统自带的工具【tasklist.exe】 利用 QProcess调用这个tasklist有一点坑,已经在代码中指出了。 指定为csv格式输出的话,在后处理时比较方便。 QList<quint64> listProcessIdentifier(QString processName) {QProcess process;QStrin…...
8.1-java+tomcat环境的配置+代理
一、回顾 1.安装nodejs,这是一个jdk一样的软件运行环境 yum -y list installed|grep epel yum -y install nodejs node -v 2.下载对应的nodejs软件npm yum -y install npm npm -v npm set config .....淘宝镜像 3.安装vue/cli command line interface 命令行…...
gorm框架实现基本的增删改查
连接数据库 package mainimport ("github.com/jinzhu/gorm"_ "github.com/jinzhu/gorm/dialects/mysql" )func main() {db, err : gorm.Open("mysql","root:roottcp(127.0.0.1:3306)/test?charsetutf8mb4&parseTimeTrue&locLocal…...
AUTOSAR介绍
1、AUTOSAR架构介绍 AUTOSAR(AUTomotive Open System ARchitecture,汽车开放系统架构)是汽车和软件行业领先公司的全球合作联盟,为智能移动开发和建立标准化的软件框架以及开放的E/E系统架构。考虑到目前和未来市场中不同的汽车E/E架构,AUTOS…...
10. 计算机网络HTTP协议
1. 前言 无论是作为后端开发、前端开发、测试开发程序员或者是运维人员,在面试过程中,大概率都会被问到 HTTP 协议相关题目。 因为伴随着 2010 年之后移动互联网在全世界的高速发展,各种各样的浏览器(Chrome、FireFox、Safari 等)层出不穷,也诞生了诸多服务端开发的语言…...
“职场中,不要和上司作对”,真的很重要吗?你认同这句话吗?
在职场上,领导对下属的期望永远都只有两个字,不是忠诚,也不是能力,而是省心。 领导对下属的要求就是别让我操心。 在职场中,通常面临的首要问题就是如何与领导相处。 把职场中的前辈当作老师来尊重,你尊…...
可视化目标检测算法推理部署(一)Gradio的UI设计
引言 在先前RT-DETR模型的学习过程中,博主自己使用Flask框架搭建了一个用于模型推理的小案例: FlaskRT-DETR模型推理 在这个过程中,博主需要学习Flask、HTML等相关内容,并且博主做出的页面还很丑,那么,是…...
【PyTorch】基于YOLO的多目标检测项目(一)
【PyTorch】基于YOLO的多目标检测项目(一) 【PyTorch】基于YOLO的多目标检测项目(二) 目标检测是对图像中的现有目标进行定位和分类的过程。识别的对象在图像中显示有边界框。一般的目标检测方法有两种:基于区域提议的…...
spring boot 实现 Stream 钉钉事件订阅
1: 参考链接 https://open.dingtalk.com/document/orgapp/develop-stream-mode-push-server 2:钉钉开放平台订阅配置 配置之后运行一下上面提供的链接 里面的main方法,验证通道 3:订阅启动方式 EventListenerThread eventListenerThrea…...
基于 Rough.js 的 Vue 散点图绘制
本文由ScriptEcho平台提供技术支持 项目地址:传送门 基于 Rough.js 的 Vue 散点图绘制 应用场景 本代码展示了如何使用 Rough.js 库在 Vue 应用程序中绘制散点图。Rough.js 是一个轻量级 JavaScript 库,用于创建具有手绘风格的可视化效果。散点图是一…...
【c++】用c++指针传递来模拟“靶向治疗”
一:源码: #include <iostream>void targetedTherapy(bool* flag) {if (*flag == false) {*flag = true;} }int main() {//代表一系列癌细胞//true为健康细胞 false为癌变细胞bool cancerCell[7] = {true, false, true, true, true, true, false};for (int i = 0; i &…...
如何开启idea中的断言功能?
目录 一、什么是断言? 二、Java断言的语法 三、开启断言 一、什么是断言? 断言(assert)是 Java 中的一条语句,一种在程序中的逻辑(如一个结果为真或假的逻辑判断式),目的是验证软…...
大模型之语言大模型技术
本文作为大模型综述第二篇,介绍语言大模型基本技术。 近年来,在 Transformer 架构基础上构建的预训练语言模型为自然语言处理领域带来了一系列突破式进展,成为人工智能主流技术范式。预训练语言模型采用“预训练+微调”方法,主要分为两步: 1)将模型在大规模无标注数据上…...
浮点数例外 (核心已转储) 的问题记录
一般这种问题,是程序运行过程中出现浮点数运算错误导致的程序崩溃 浮点异常可能由以下几个原因引起: 除以零:当程序中出现除以零的操作时,会触发浮点异常。例如,当一个数除以0时,会导致浮点异常。数值溢出…...
Vite项目中根据不同打包命令配置不同的后端接口地址,proxy解决跨域
在vite.config.ts同级目录添加两个文件 .env.development #开发环境 VITE_APP_ENV developmentVITE_APP_BASE_API .env.production #生产配置 VITE_APP_ENV productionVITE_APP_BASE_API https://www.bdjw.work代码中使用路径 const request axios.create({baseURL: i…...
Java新手启航:JDK 21 版本安装,开启编程之行
在Java开发前,JDK是必不可少的环境,接下来,让我们一起完成JDK 21版本的下载和安装! 种一棵树最好的时间是10年前,其次就是现在,加油! …...
Redis学习[5] ——Redis过期删除和内存淘汰
六、Redis过期键值删除 6.1 Redis的过期键值删除策略 6.1.1 什么是过期键值删除? Redis中是可以对key设置过期时间的,所以需要有相应的机制将已过期的键值对删除,也就是**过期键值删除策略。Redis会用一个过期字典(expires dic…...
书生大模型学习笔记 - Python
Python实现wordcount 请实现一个wordcount函数,统计英文字符串中每个单词出现的次数。返回一个字典,key为单词,value为对应单词出现的次数。 解题思路:首先把字母转小写>然后把单词取出来去除标点>循环单词列表>key已存…...
JavaScript青少年简明教程:面向对象编程入门
JavaScript青少年简明教程:面向对象编程入门 JavaScript 支持多种编程范式(programming paradigms),即支持多种不同的编程风格和方法。 前面介绍的编程方式,主要是面向过程编程(Procedural Programming&am…...
电话号的标准
点击标题下「蓝色微信名」可快速关注 最近碰到个电话号码的问题,除了常规数字,可能还会有国内国际的区号,例如中国,86、086、86,这些好像都见过,但什么是标准的?谁来定义的? 国际电信…...
项目实战_表白墙(升级版)
你能学到什么 表白墙(升级版)Mybatis的一些简单应用 正文 前⾯的案例中, 我们写了表⽩墙, 但是⼀旦服务器重启, 数据就会丢失. 要想数据不丢失, 需要把数据存储在数据库中,接下来咱们借助MyBatis来实现数据库的操作。 数据准备 如果我们…...
徐州市水利工程建设有限公司网站/网络营销公司好不好
1.什么是分布式锁 线程锁主要用来给方法,代码加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行改方法或改代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,进程锁是为了控制…...
网店开店流程步骤/谷歌seo怎么优化
一、先凑整,再补零例如:17 34 ----> 20 30 50 --> 50 1 51二、利用数字的特征例如 17 x 23 ---> (20 - 3) x (20 3) 400 - 9 391三、记住一下开方 1 ~ 10的开方 根号 1 1 根号 6 2.44…...
日本建设网站/搜狗指数官网
public class LayoutAnimationController extends Object java.lang.Object ↳ android.view.animation.LayoutAnimationController 可以看出LayoutAnimationController类直接继承Object类,用于在组件上添加一些动画效果,这些组件包括常用的ListVie…...
wordpress例子/百度爱采购服务商查询
首先,需要打开终端,若桌面没有终端图标,则可以使用ctrlaltt即可,之后将终端锁定在任务栏。 其次,需要获取root权限,使用命令 su root 密码(我的是root)。 进入之后,…...
四川省网站建设/长沙网站seo推广公司
Windows Shell提供的编辑控件Edit Control(注意不是Rich Edit)没有垂直对齐的风格,在这样的控件中显示文本时可以观察到文本总是顶端对齐,虽然说可以在WM_PAINT消息中绘制文本的位置,可以使其垂直对齐,但这样到鼠标的光标也不会垂…...
做网站大概需要多少费用/关键词优化seo优化排名
IT培训费用一般都是1W以上,因而想学IT的大学生们在选择培训机构时会犹豫很久,一是自身经济不自由,二是培训效果没人保证,而CSDN推出的超级实习生公开保障培训效果,费用等同于IT培训,应该怎么选呢? IT培训…...