由于Java的JVM引入了垃圾回收机制,垃圾回收器会自动回收不再使用的对象,JVm是使用可达性分析算法来判断对象是否不再使用的对象,本质都是判断一个对象是否还被引用。那么对于这种情况下,由于代码的实现不同就会出现很多种内存泄漏问题(让JVM误以为此对象还在引用中,无法回收,造成内存泄漏)

一、静态集合类

如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。简单而言,长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。

二、各种连接,如数据库连接、网络连接和IO连接等

在对数据库进行操作的过程中,首先需要建立与数据库的连接,当不再使用时,需要调用close方法来释放与数据库的连接。只有连接被关闭后,垃圾回收器才会回收对应的对象。否则,如果在访问数据库的过程中,对Connection、Statement或ResultSet不显性地关闭,将会造成大量的对象无法被回收,从而引起内存泄漏。

三、变量不合理的作用域

一般而言,一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为null,很有可能导致内存泄漏的发生。

public class UsingRandom {private String msg;public void receiveMsg(){readFromNet();// 从网络中接受数据保存到msg中saveDB();// 把msg保存到数据库中}
}

如上面的伪代码,通过readFromNet方法把接受的消息保存在变量msg中,然后调用saveDB方法把msg的内容保存到数据库中,此时msg已经就没用了,由于msg的生命周期与对象的生命周期相同,此时msg还不能回收,因此造成了内存泄漏。

实际上这个msg变量可以放在receiveMsg方法内部,当方法使用完,那么msg的生命周期也就结束,此时就可以回收了。还有一种方法,在使用完msg后,把msg设置为null,这样垃圾回收器也会回收msg的内存空间。

四、内部对象持有外部类

如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。

五、改变哈希值

当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露

六、缓存泄漏

内存泄漏的另一个常见来源是缓存,一旦你把对象引用放入到缓存中,他就很容易遗忘,对于这个问题,可以使用WeakHashMap代表缓存,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值

代码示例:

package com.ratel.test;/*** @业务描述:* @package_name: com.ratel.test* @project_name: ssm* @author: ratelfu@qq.com* @create_time: 2019-04-18 20:20* @copyright (c) ratelfu 版权所有*/
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;public class MapTest {static Map wMap = new WeakHashMap();static Map map = new HashMap();public static void main(String[] args) {init();testWeakHashMap();testHashMap();}public static void init(){String ref1= new String("obejct1");String ref2 = new String("obejct2");String ref3 = new String ("obejct3");String ref4 = new String ("obejct4");wMap.put(ref1, "chaheObject1");wMap.put(ref2, "chaheObject2");map.put(ref3, "chaheObject3");map.put(ref4, "chaheObject4");System.out.println("String引用ref1,ref2,ref3,ref4 消失");}public static void testWeakHashMap(){System.out.println("WeakHashMap GC之前");for (Object o : wMap.entrySet()) {System.out.println(o);}try {System.gc();TimeUnit.SECONDS.sleep(20);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("WeakHashMap GC之后");for (Object o : wMap.entrySet()) {System.out.println(o);}}public static void testHashMap(){System.out.println("HashMap GC之前");for (Object o : map.entrySet()) {System.out.println(o);}try {System.gc();TimeUnit.SECONDS.sleep(20);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("HashMap GC之后");for (Object o : map.entrySet()) {System.out.println(o);}}}
/** 结果String引用ref1,ref2,ref3,ref4 消失WeakHashMap GC之前obejct2=chaheObject2obejct1=chaheObject1WeakHashMap GC之后HashMap GC之前obejct4=chaheObject4obejct3=chaheObject3Disconnected from the target VM, address: '127.0.0.1:51628', transport: 'socket'HashMap GC之后obejct4=chaheObject4obejct3=chaheObject3**/![在这里插入图片描述](https://img-blog.csdnimg.cn/20200904184044946.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2traW5nX2VkYw==,size_16,color_FFFFFF,t_70#pic_center)

上面代码和图示主演演示WeakHashMap如何自动释放缓存对象,当init函数执行完成后,局部变量字符串引用weakd1,weakd2,d1,d2都会消失,此时只有静态map中保存中对字符串对象的引用,可以看到,调用gc之后,hashmap的没有被回收,而WeakHashmap里面的缓存被回收了。

七、监听器和回调

内存泄漏第三个常见来源是监听器和其他回调,如果客户端在你实现的API中注册回调,却没有显示的取消,那么就会积聚。需要确保回调立即被当作垃圾回收的最佳方法是只保存他的若引用,例如将他们保存成为WeakHashMap中的键。

八、一个例子


import java.util.Arrays;public class Stack {private Object[] elements;private int size = 0;private static final int DEFAULT_INITIAL_CAPACITY = 16;public Stack() {elements = new Object[DEFAULT_INITIAL_CAPACITY];}public void push(Object e) {ensureCapacity();elements[size++] = e;}public Object pop() {if (size == 0)throw new EmptyStackException();return elements[--size];}private void ensureCapacity() {if (elements.length == size)elements = Arrays.copyOf(elements, 2 * size + 1);}
}

8.1 原因分析

上述程序并没有明显的错误,但是这段程序有一个内存泄漏,随着GC活动的增加,或者内存占用的不断增加,程序性能的降低就会表现出来,严重时可导致内存泄漏,但是这种失败情况相对较少。
代码的主要问题在pop函数,下面通过这张图示展现
假设这个栈一直增长,增长后如下图所示

当进行大量的pop操作时,由于引用未进行置空,gc是不会释放的,如下图所示:

从上图中看以看出,如果栈先增长,在收缩,那么从栈中弹出的对象将不会被当作垃圾回收,即使程序不再使用栈中的这些队象,他们也不会回收,因为栈中仍然保存这对象的引用,俗称过期引用,这个内存泄露很隐蔽。

8.2 解决方法

public Object pop() {if (size == 0)throw new EmptyStackException();Object result = elements[--size];elements[size] = null;return result;
}

一旦引用过期,清空这些引用,将引用置空。

参考文章

Java中内存泄漏八种情况的总结相关推荐

  1. java服务器内存问题_java内存泄漏5种情况总结

    内存泄漏定义:一个不再被程序使用的对象或变量还在内存中占有存储空间. 由于java的JVM引入了垃圾回收机制,垃圾回收器会自动回收不再使用的对象,了解JVM回收机制的都知道JVM是使用引用计数法和可达 ...

  2. linux c 指针 内存 泄漏几种情况

    引言 对于任何使用C语言的人,如果问他们C语言的最大烦恼是什么,其中许多人可能会回答说是指针和内存泄漏.这些的确是消耗了开发人员大多数调试时间的事项.指针和内存泄漏对某些开发人员来说似乎令人畏惧,但是 ...

  3. java static内存泄漏_Java中的内存泄漏

    内存泄漏是指不再使用的对象持续占有内存空间而得不到及时释放,从而造成内存空间的浪费称为内存泄漏.比如,长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是 ...

  4. Java中的OutOfMemoryError的各种情况及解决方法

    转载自博客园:https://www.cnblogs.com/duanxz/p/4901437.html Java中的OutOfMemoryError的各种情况及解决和JVM内存结构 在JVM中内存一 ...

  5. 使用Java创建内存泄漏

    我刚刚接受采访,并被要求使用Java造成内存泄漏 . 不用说,我对如何开始创建它一无所知. 一个例子是什么? #1楼 最近,我遇到了一种更细微的资源泄漏. 我们通过类加载器的getResourceAs ...

  6. JAVA中的引用四种引用类型

    关于值类型和引用类型的话题,C++.JAVA.python.go.C#等等高级语言都有相关的概念,只要理解了其底层工作原理,可以说即使是不同的语言,在面试学习工作实践中都可以信手拈来(不要太纠集语言) ...

  7. java程序内存泄漏场景及预防

    为什么80%的码农都做不了架构师?>>>    虽然jvm有垃圾回收机制,如果程序编写不注意某些特定规则,仍然会导致java程序内存泄漏,最终可能出现OutOfMemory异常. 1 ...

  8. Android 中内存泄漏的原因和解决方案

    之前研究过一段时间关于 Android 内存泄漏的知识,大致了解了导致内存泄漏的一些原因,但是没有深入去探究,很多细节也理解的不够透彻,基本上处于一种似懂非懂的状态,最近又研究了一波,发现有很多新的收 ...

  9. Java中对象的三种状态

    转载自   Java中对象的三种状态 Java中的对象的三种状态是和垃圾回收紧密相关的,因此有必要深究. 状态一:可触及态:从根节点开始,可以搜索到这个对象,也就是可以访问到这个对象,也有人将其称为可 ...

  10. VC++6.0中内存泄漏检测 转

    最近看了周星星 Blog 中的一篇文章:"VC++6.0中内存泄漏检测",受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了 ...

最新文章

  1. 部署Configuration Manager主站点以及辅助站点
  2. 10没有基于策略的qos_基于强化学习的用户移动场景下空中基站3D位置高效部署...
  3. Docker入门到实践
  4. 【渝粤教育】国家开放大学2018年春季 0579-22T电路及磁路(2)(一) 参考试题
  5. pgsql转储_十六进制转储如何工作
  6. 金山办公:2021年净利润10.42亿元,同比增长19%
  7. 为什么要使用 dns-prefetch
  8. html返回按钮 超链接,ppt中怎么添加超链接返回按钮
  9. 测试用例-1-微信发红包功能
  10. 上海计算机等级考试档案记录,【档案区】上海市高等学校计算机等级考试(一级)考试大纲...
  11. C#事件和委托的区别
  12. 显卡驱动程序如何更新
  13. Java汉字转换拼音工具类
  14. cp: omitting directory xxx
  15. bmi计算 python_《Python之BMI计算》
  16. WPF加载obj模型-2
  17. Python矩阵分解之QR分解
  18. 拓扑学 -- from BBS 水木清华站
  19. 使用管道完成父子进程间通信
  20. 等离子表面处理的原理,等离子表面处理机-金铂利莱

热门文章

  1. 设计模式-02-创建型模式详解
  2. linux系统man命令空白键,man查看帮助命令
  3. Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天
  4. java 不安全操作_Java新手求助:怎么会出现使用了未经检查或不安全的操作。
  5. 前端绝对路径不显示图片_Vue cli使用绝对路径引用图片问题的解决_情愫_前端开发者...
  6. 华为手机设置页面黑色_羡慕黑色背景照片?华为手机简单一招即可轻松拍摄
  7. 学生选课系统的源码---架构图MVC1
  8. java案例代码17--正则表达式小案例
  9. tomcat-9.0.20部署的问题及性能监控
  10. 关于iis w3wp.exe