原文网址:Java内存泄露系列--内存泄露的原因及解决方案(大全)_IT利刃出鞘的博客-CSDN博客

简介

简介

本文介绍Java中内存泄露的一些原因与解决方案。

如果内存泄露的空间足够大,就会导致内存溢出(OOM)。

内存泄露的原因

堆内存中一个对象不再使用时,垃圾回收器却无法从内存中删除他们,导致内存泄露。

内存泄露的影响

  • 长时间连续运行时性能严重下降;
  • 出现OOM导致应用崩溃;

内存泄露的检测与分析

通常我们可以借助MAT、LeakCanary等工具来检测应用程序是否存在内存泄漏。

1、MAT是一款强大的内存分析工具,功能繁多而复杂。
2、LeakCanary则是由Square开源的一款轻量级的第三方内存泄漏检测工具,当检测到程序中产生内存泄漏时,它将以最直观的方式告诉我们哪里产生了内存泄漏和导致谁泄漏了而不能被回收。

内存泄露的类型

主要有以下类型:

  1. ThreadLocal
  2. static字段
  3. 未关闭的资源
  4. 集合容器
  5. 改变哈希值
  6. 内部类持有外部类
  7. finalize()方法
  8. 常量字符串

ThreadLocal

相关网址

Java的ThreadLocal导致内存泄露----原因/解决方案_IT利刃出鞘的博客-CSDN博客

简介

使用ThreadLocal时,每个线程只要处于存货状态就可保留对其ThreadLocal变量副本的隐式调用,且将保留其自己的副本。使用不当,就会引起内存泄露。

一旦线程不在存在,ThreadLocals就应该被垃圾收集,而现在线程的创建都是使用线程池,线程池有线程重用的功能,因此线程就不会被垃圾回收器回收。所以使用到ThreadLocals来保留线程池中线程的变量副本时,ThreadLocals没有显示的删除时,就会一直保留在内存中,不会被垃圾回收。

解决方法

  1. 不再使用ThreadLocal时,调用remove()方法,该方法删除了此变量的当前线程值。
  2. 不要使用ThreadLocal.set(null),它只是查找与当前线程关联的Map并将键值对设置为当前线程为null。

static字段

简介

大量使用static字段会潜在的导致内存泄露,在Java中,静态字段通常拥有与整个应用程序相匹配的生命周期。

示例:单例的静态特性使得其生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而单例对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。

解决方法

  1. 最大限度的减少静态变量的使用;
  2. 单例模式时,依赖于延迟加载对象而不是立即加载方式。

未关闭的资源

简介

对于使用了BroadcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。

解决方法

调用它的close()函数将其关闭掉,然后再设置为null

注意

  1. 一般使用finally块关闭资源;关闭资源的代码,不应该有异常;
  2. jdk1.7后,可以使用try-with-resource块。

集合容器

简介

我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,如果在不需要该对象时,没有把对象的引用从集合中清理掉,这样这个集合就会越来越大。

如果这个List是临时的,那没问题,List被回收后里边的对象引用也就不会被持有了(对象不可达),对象引用也会被回收。如果这个List不是临时的,那么就会导致内存占用越来越大。

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

解决方法

  1. 如果是static类型的集合,在退出程序之前,将集合里的东西clear,然后置为null,再退出程序。

改变哈希值

简介

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

解决方法 

  1. 不要修改这个对象中的那些参与计算哈希值的字段

内部类持有外部类

相关网址

Java的内部类持有外部类导致内存泄露--原因/解决方案_IT利刃出鞘的博客-CSDN博客

简介

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

在Java中,非静态内部类和匿名类内部类都会潜在持有它们所属的外部类的引用,但是静态内部类却不会。

解决办法

  1. 如果内部类不需要访问外部类成员,考虑转换为静态内部类。

finalize()方法

简介

重写finalize()方法时,该类的对象不会立即被垃圾收集器收集,如果finalize()方法的代码有问题,那么会潜在的引发OOM;

解决办法

  1. 尽量避免重写finalize();或者保证finalize方法没问题

常量字符串

简介

如果我们读取一个很大的String对象,并调用了intern(),那么它将放到字符串池中,位于PermGen中,只要应用程序运行,该字符串就会保留,这就会占用内存,可能造成OOM。

解决方法

  • 增加PermGen的大小,-XX:MaxPermSize=512m;
  • 升级Java版本,JDK1.7后字符串池转移到了堆中。

其他网址

8种JVM内存溢出(OOM)的原因和解决方法--掘金

Java中的内存泄露问题 及解决方法_java_多多-CSDN博客
彻底搞懂Java内存泄露 - 简书
java中内存泄露8种情况的总结_java_ratel的博客-CSDN博客

Java内存泄露系列--内存泄露的原因及解决方案(大全)相关推荐

  1. 内存溢出和内存泄漏的区别、产生原因以及解决方案

    内存溢出和内存泄漏的区别.产生原因以及解决方案 参考文章: (1)内存溢出和内存泄漏的区别.产生原因以及解决方案 (2)https://www.cnblogs.com/ziyoublog/p/1038 ...

  2. java.lang.NullPointerException出现的几种原因及解决方案

    java.lang.NullPointerException是java编程中最常见的异常之一.任何使用java的人都有在java程序以及java web应用程序中看到java.lang.NullPoi ...

  3. java并发编程系列-内存模型基础

    java线程之间的通信对程序开发人员是完全透明的,内存的可见性问题很容易困扰很多开发人员.本篇博文将揭开java内存模型的神秘面纱,来看看内存模型到底是怎样的. 并发编程中需要处理的两个关键问题: · ...

  4. 内存溢出和内存泄漏的区别、产生原因以及解决方案 转

    内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出. ...

  5. 内存溢出和内存泄漏的区别,产生原因以及解决方案

    一.概念与区别 内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如申请了一个integer,但给它存了long才能存下的数,那 ...

  6. Chrome“喔唷,崩溃啦!”内存不足引起页面崩溃的原因和解决方案

    前言: 还"喔唷,崩溃啦"?卖萌也没有用,你不行还不改,那我只好另请高明了.使用火狐浏览器可以避免此问题. 问题描述: 虽然很少遇到,但确实只要Chrmoe单个页面占用内存超过4G ...

  7. Java中equals方法造成空指针异常的原因及解决方案

    前言 博主最近在做一个项目的调试工作,期间遇到了一个会导致抛出空指针异常的小问题,说它是小问题,是因为真的只是在写代码的时候注意一下就好了,但是这里还要写一个博客,就是为了剖析这个问题,然后给自己做个 ...

  8. Java内存泄漏系列--匿名内部类导致内存泄露--原因/解决方案

    原文网址:Java内存泄漏系列--匿名内部类导致内存泄露--原因/解决方案_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用示例介绍匿名内部类会导致内存泄漏的原因及其解决方案. 相关网址 普通内部 ...

  9. Java内存泄露系列--内部类持有外部类导致内存泄露--原因/解决方案

    原文网址:Java内存泄露系列--内部类持有外部类导致内存泄露--原因/解决方案_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java内部类持有外部类导致内存泄露的原因以及其解决方案. 为什么内部 ...

最新文章

  1. 点击改变div高度_css实现div两列布局(两种方法)
  2. 深入理解angularjs $watch ,$apply 和 $digest --- 理解数据绑定过程
  3. 如何使VS2008 调试网站的根目录和IIS调试的一致?
  4. 在开发环境中,自己搭建一个ssl环境(小例子)
  5. sql: table,view,function, procedure created MS_Description in sql server
  6. 浅析托管与非托管C++代码(转)
  7. 过滤器Filter与监听器Listener
  8. CAD 使用 颜色 线型
  9. 电脑进入pe时蓝屏_进入PE系统就蓝屏怎么办?
  10. 树莓派USB摄像头的使用
  11. ubuntu14.04_cuda8.0_cuDnn5.0_python3.4_gtx750ti_tensorflow
  12. cs系统的服务器地址,《反恐精英CS》服务器地址
  13. Android studio gradle编译失败问题汇总
  14. u盘安装原版win10
  15. grep 忽略大小写、忽略grep命令本身
  16. JAVA基础-50道编程题
  17. 搭建运营工单数据分析系统
  18. Linux系统的常见命令记忆【Ubuntu】
  19. css(显示与隐藏、溢出)
  20. Fetion 操作台

热门文章

  1. 英文系统下玩中文版魔兽
  2. 中国计算机科学期刊,计算机科学杂志是核心期刊吗?
  3. [附源码]计算机毕业设计JAVA汽车租赁管理系统论文
  4. 烽火HG680L_S905L-3B_线刷固件包(河北联通2021年4月高安版)
  5. Infiniband
  6. open函数和fopen函数区别
  7. C++【二叉搜索树】
  8. JAVA练习 ——火车
  9. 02 【字符实体与语义标签(上)】
  10. 王者服务器维护时间表2020,王者荣耀维护几点结束2020