内存泄漏是指不再使用的对象持续占有内存空间而得不到及时释放,从而造成内存空间的浪费称为内存泄漏。比如,长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收,这就是Java中内存泄漏的发生场景。所有的内存泄露,最后都会抛出OutOfMemoryError异常。

一、内存泄漏的常见情况

1.static字段引起的内存泄漏

可能导致潜在内存泄漏的第一种情况是大量使用static变量。在Java中,静态字段通常拥有与整个应用程序相匹配的生命周期(除非ClassLoader符合垃圾回收的条件)。

来看下面这段程序:

public classStaticTest {public static List list = new ArrayList<>();public voidpopulateList() {for (int i = 0; i < 10000000; i++) {

list.add(Math.random());

}}public static voidmain(String[] args) {newStaticTest().populateList();}

}

运行前打开visualvm, 然后运行程序,visualvm就会进行监控到运行程序的进程。

如何预防呢?

最大限度地减少静态变量的使用

使用单例时,依赖于延迟加载对象而不是立即加载的方式

2.资源未关闭导致内存泄漏

①数据库连接,网络连接(socket)和io连接,需要显式的调用close方法将其连接关闭,否则是不会自动被GC 回收的。

②锁资源未释放,导致线程泄漏。比如ReentrantLock用完,记得用lock.unlock()来释放锁。

如何预防呢?

始终使用finally块来关闭资源

关闭资源的代码(甚至在 finally块中)本身不应该有任何异常

使用Java 7+时,我们可以使用try -with-resources块

3.hashcode数据结构产生的内存泄漏

典型案例1:一个没有实现hasCode和equals方法的Key类在HashMap中保存的情况。最后会生成很多重复的对象。

/*** HashMap中,由于Key没有实现euqals和hashCode方法,导致可以重入添加,造成内存泄漏。*/

public classKeyWithoutEqualsAndHashCode {public static voidmain(String[] args) {

Map map = new HashMap(1000);while (true) {//creates duplicate objects due to bad Key class

Person dummyKey = new Person("zhangsan", 18);//可重复添加,导致内存泄漏

map.put(dummyKey, "value");

}

}static classPerson {privateString name;private intage;

Person(String name,intage) {this.name =name;this.age =age;

}//省略getter/setter

/*@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

Person person = (Person) o;

if (age != person.age) return false;

return name != null ? name.equals(person.name) : person.name == null;

}

@Override

public int hashCode() {

int result = name != null ? name.hashCode() : 0;

result = 31 * result + age;

return result;

}*/}

}

使用jps查看java进程,找到程序对应的进程pid,再使用jconsole pid号启动jconsole查看监控。

典型案例2:当集合里面的对象属性被修改后,再调用remove()方法不起作用,造成内存泄漏。

/*** 修改了存入Hash结构中的元素的属性,导致hash改变。因此无法再获取到该元素,造成内存泄漏。*/

public classUpdateFieldOfElementInHashSet {public static voidmain(String[] args) {

Set set = new HashSet(1000);while (true) {

Person dummyPerson= new Person("zhangsan", 18);

set.add(dummyPerson);

dummyPerson.setAge(28);//修改age属性,导致hash变化//hash已变,找不到,无法移除

set.remove(dummyPerson);

}

}

}static classPerson {privateString name;private intage;

Person(String name,intage) {this.name =name;this.age =age;

}//省略getter/setter

@Overridepublic booleanequals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;

Person person=(Person) o;if (age != person.age) return false;return name != null ? name.equals(person.name) : person.name == null;

}

@Overridepublic inthashCode() {int result = name != null ? name.hashCode() : 0;

result= 31 * result +age;returnresult;

}

}

}

如何预防呢?

根据经验,定义新的实体时,总要重写equals()和hashCode()方法。

只是重写他们是不够的,这些方法必须以最佳的方式被重写。

4.ThreadLocal

ThreadLocal用完一定要remove,否则可能会造成内存泄漏。

5.监视器(Listener)未释放

web开发中经常会用到监视器(Listener),但在释放对象的时候却没有去删除这些监听器,增加了内存泄漏的机会。

6.内部类和外部模块的引用

这种情况发生在非静态内部类(匿名类)的情况下。对于初始化,这些内部类总是需要外部类的实例。

默认情况下,每个非静态内部类都包含对其包含类的隐式引用。如果我们在应用程序中使用这个内部类对象,那么即使在我们的包含类对象超出范围之后,它也不会被垃圾收集。

如何预防呢?

如果内部类不需要访问包含的类成员,可以考虑将其转换为静态类

二、如何排查内存泄漏问题

真实案例分享:

参考文章:

java static内存泄漏_Java中的内存泄漏相关推荐

  1. java imageio 内存问题_java中的内存泄漏ImageIO.read()

    我正在使用ImageIO.read().这是由原始应用的主要方法调用的类是这样的:java中的内存泄漏ImageIO.read() import java.awt.*; import javax.sw ...

  2. java 内存溢出和内存泄漏_JAVA中的内存溢出和内存泄漏有很大的区别

    JAVA中的内存溢出和内存泄漏分别是什么,有什么联系和区别,我谈谈自己的理解. 内存泄漏(memory leak ):申请了内存不释放,比如100m的内存,分配了10m的内存一直不回收,那么可以用的内 ...

  3. java final内存机制_Java中的内存处理机制和final、static、final static总结

    装载自:http://blog.csdn.net/wqthaha/article/details/20923579 Java程序运行在JVM上,可以把JVM理解成Java程序和操作系统之间的桥梁,JV ...

  4. java static调用吗_Java中的static的使用

    1.Java 中被static修饰的成员称为静态成员或类成员.它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享.且优先于对象存在.静态成员可以使用类名直接访问,也可以使用对象名进行访问.使 ...

  5. java static 变量共享_java中如何理解多个对象共享同一个静态成员变量?

    展开全部 要理解这个问题首先要知道一点,就是java的静态成62616964757a686964616fe59b9ee7ad9431333433643133员变量是有一个独立的存储空间的. 假设一个类 ...

  6. java static调用吗_java中使用static

    使用: 1.类成员变量 2.类方法 1.类方法中不能有非静态成员.因 为非静态成员与实例相关,通过对象间接使用. 2.不能使用this. 3.static块:和数据成员时并列的位置,用于类初始化类装入 ...

  7. linux gdb打印内存命令,gdb中查看内存方法总结

    出自计组第三次上机附加题第二题 用gdb运行程序b,输出中相应地址究竟指向了什么? 请贴上你是如何找到的(使用了什么gdb指令等等) 在查看地址前首先需要断点定位到需要查看的位置 显示代码内容 (gd ...

  8. java 内存 静态_java中内存分配以及static的用法(转)

    JAVA能够实现跨平台的一个根本原因,是定义了class文件的格式标准,凡是实现该标准的JVM都能够加载并解释该class文件,据此也可以知道,为啥Java语言的执行速度比C/C++语言执行的速度要慢 ...

  9. java 内存溢出和内存泄漏_java中内存溢出和内存泄漏的区别

    虽然在java中我们不用关心内存的释放, 垃圾回收机制帮助我们回收不需要的对象,但实际上不正当的操作也会产生内存问题:如,内存溢出.内存泄漏 内存溢出:out of memory:简单通俗理解就是内存 ...

最新文章

  1. Springboot监控之一:SpringBoot四大神器之Actuator之3-springBoot的监控和管理--指标说明...
  2. VK1629A 驱动芯片
  3. Qt中的QStackedLayout
  4. [LGP4707] 重返现世
  5. 返回对应对象的克隆方法
  6. RISC-V踩坑记----__builtin_clz((x)库函数的应用
  7. 计算机应用基础教材6,全国2013年自考《计算机应用基础》教材大纲第六章
  8. 收获,不止SQL优化——抓住SQL的本质--读过程
  9. python函数格式化_Python通过format函数格式化显示值
  10. Data Minig --- Decision Tree ID3 C4.5 Gini Index
  11. python cursor函数_执行从python返回cursor的db2plsql函数
  12. 云和恩墨大讲堂西安站成功举办,携手合作伙伴引领企业数字化转型
  13. 小趴菜学习c语音记录第六天
  14. c语言程序设计需要学多久,九江c语言编程学习,九江学c语言编程报班,九江学c语言编程一般要多久才能学会...
  15. 使用python脚本将word文档转txt
  16. java实现简单的LUR算法
  17. L3-020 至多删三个字符 (30分)(动态规划)
  18. 解读视联网发展阶段之成年篇
  19. RocketMQ 关于 No route info of this topic 问题
  20. java 同步数据,同步数据到另一个库中。

热门文章

  1. 一步步教你如何在SpringBoot项目中引入支付功能
  2. UE4实战记录(一)让物体向前飞行
  3. Simulink 自动代码生成电机控制:自动定点化Fixed-Point Tool 使用
  4. 【数字电路】在我的世界中学习数字电路知识
  5. NVIDIA Jetson TX2 挂载SSD硬盘
  6. 转:在不同的境遇中去求一个“安”
  7. 碧玉刀服务器维护,碧玉刀-流云:爱恨交并
  8. 【算法】穷举法习题练习
  9. K8S + RANCHER 随记
  10. 默认应用老是弹窗问题