转自:https://blog.csdn.net/weter_drop/article/details/89387564

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

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

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

3、变量不合理的作用域。一般而言,一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为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的内存空间。

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

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

6.举个例子-看你能否找出内存泄漏


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);}
}

6.1原因分析

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

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

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

1.2解决方法

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

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

7.缓存泄漏

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

7.1代码示例

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**/


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

8.监听器和回调

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

Java内存泄露8种情况的总结相关推荐

  1. Java内存泄露系列--内存泄露的原因及解决方案(大全)

    原文网址:Java内存泄露系列--内存泄露的原因及解决方案(大全)_IT利刃出鞘的博客-CSDN博客 简介 简介 本文介绍Java中内存泄露的一些原因与解决方案. 如果内存泄露的空间足够大,就会导致内 ...

  2. Java内存泄露的理解与解决

    Java内存管理机制 在C++语言中,如果需要动态分配一块内存,程序员需要负责这块内存的整个生命周期.从申请分配.到使用.再到最后的释放.这样的过程非常灵活,但是却十分繁琐,程序员很容易由于疏忽而忘记 ...

  3. java线程泄露_面试官:小伙子先来说一下可能引起Java内存泄露的场景吧

    原标题:面试官:小伙子先来说一下可能引起Java内存泄露的场景吧 本文分析一下可能引起java内存泄露的场景: 通过 finalize 方法 终结器finalizers的使用是潜在内存泄漏问题的另一个 ...

  4. Java内存泄露和内存溢出、JVM命令行工具、.JDK可视化工具、Java Class文件

    1.Java内存泄露和内存溢出对比 1.1 Java 内存泄露 内存泄露是指一个不再被程序使用的对象或变量还在内存中占用空间. 1.1.1判断内存空间是否符合垃圾回收的标准 在Java语言中,判断一个 ...

  5. java内存泄露有什么后果,Java内存泄露问题是什么?

    很多人在谈论内存泄露问题,当然对于c/c++来说,这个应该是老掉牙的问题,但是很多Java人员也越来越多得讨论这个问题,我这里写个小结,希望对大家有一定的参考价值. 内存泄漏的慨念 1.c/c++是程 ...

  6. Java 内存泄露以及避免方法

    转载自  Java 内存泄露以及避免方法 内存泄露:      是指在程序运行过程中会不断的分配内存空间,那些不再使用的内存空间应该即时回收它们,从而保证可以保证系统可以再次使用这些内存.如果存在无用 ...

  7. Java内存泄露原因详解

    一.Java内存回收机制  不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址.Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(He ...

  8. JAVA内存泄露分析和解决方案及WINDOWS自带查看工具

    JAVA内存泄露分析和解决方案及WINDOWS自带查看工具 Java内存泄漏是每个Java程序员都会遇到的问题,程序在本地运行一切正常,可是布署到远端就会出现内存无限制的增长,最后系统瘫痪,那么如何最 ...

  9. java内存泄露分析方案

    java内存泄露分析方案 - 准备工作 1.工具:Memory Analyzer Tool (mat); 1)安装Memory Analyzer Tool (mat) 2.原料:dump.hprof ...

最新文章

  1. 30 段极简 Python 代码:这些小技巧你都 Get 了么?
  2. pxeconfig 4.2.0 发布,PXE 首要启动设备
  3. Elastricsearch 索引操作详解(快速入门、索引管理、映射详解、索引别名)
  4. sencha touch list(列表)、 store(数据源)、model(模型)详解
  5. 常考数据结构与算法:异或操作
  6. SqlSugar-事务操作
  7. Docker(四):Docker 三剑客之 Docker Compose
  8. CV:Visual Studio 2015版本+CUDA8.0+Cudnn8.0+OpenCV 3.1.0版本完美解决的详细攻略
  9. Tomcat:基础安装和使用教程
  10. Java动态解析域名
  11. java 80_【JavaWeb】80:js基础详解
  12. LeetCode 2037. 使每位学生都有座位的最少移动次数
  13. 使用JavaMail技术发送邮件
  14. 学习笔记---Web服务、Remoting、WCF (上) --- Web服务
  15. 通信原理(五) 信道编码
  16. 扫描仪标准模板滑动采集图像及其处理
  17. 乐高机器人纲要_乐高机器人校本课程纲要
  18. linux dm9000驱动分析,ARM-Linux驱动--DM9000网卡驱动分析(二)
  19. 计算机专业论文周进展300字,论文进展情况记录300字_论文周进展情况记录文库_论文进展情况18篇记录...
  20. Jupyter Notebook 工作环境配置

热门文章

  1. JDK中的23个经典设计模式【转】
  2. 诗与远方:无题(三十四)- 曾经写给妹子的一首诗
  3. Python学习笔记之元组
  4. Java8新特性总结 -5.Stream API函数式操作流元素集合
  5. anaconda安装keras_关于yolo模型的试安装及关于现阶段安排的一点想法
  6. 泉州中考分数如何计算机,2019年泉州中考总分多少分,泉州中考考试科目设置
  7. nslookup查询结果详解
  8. nginx unit
  9. SUPERSET使用笔记
  10. 加版S3(I747M)的4.4.2版本,可root