什么是内存泄露

  1. 内存管理一直是Java 所鼓吹的强大优点。开发者只需要简单地创建对象,而Java的垃圾收集器将会自动管理内存空间的分配和释放。
  2. 但在很多情况下,事情并不那么简单,在 Java程序中总是会频繁地发生内存泄露(Memory Leaks)。
  3.  
  4. 内存泄露的定义: 当某些对象不再被应用程序所使用,但是由于仍然被引用而导致垃圾收集器不能释放他们。
  5. 用白话来说就是: 该回收的内存没被回收,最后因为内存不够用而导致程序报错。
  6.  
  7. 要理解这个定义,我们需要理解内存中的对象状态。 下图展示了什么是不使用的部分,以及未被引用的部分。

  8. 从图中可以看出,内存中存在着"有引用的对象""无引用的对象" 无引用的对象将被垃圾收集器所回收,而有引用的对象则不会被当做垃圾收集。 
  9. 因为没有任何其他对象所引用,所以无引用对象一定是不再使用的,但是有一部分无用对象仍然被(无意中)引用着。这就是发生内存泄露的根源。
  10.  

为什么会发生内存泄露

  1. 为什么内存会泄露?
  2. 让我们看下面的实例来了解为什么内存会泄露。 
  3. 在下面的情境中,对象A引用了对象B A的生命周期(t1 - t4) B的(t2 - t3)要长得多。 当对象B在应用程序逻辑中不会再被使用以后, 对象 A 仍然持有着 B的引用。 (根据虚拟机规范)在这种情况下垃圾收集器不能将 B 从内存中释放,这种情况很可能会引起内存问题。甚至有可能 B 也持有一大堆其他对象的引用,这些对象由于被 B 所引用,也不会被垃圾收集器所回收。所有这些无用的对象将消耗大量宝贵的内存空间。
  4.  

发生内存泄漏的常见场景

    • 静态集合类
  1. HashMapArrayList等的使用最容易出现内存泄露,由于静态变量的生命周期和应用程序一致,所以他们所引用的所有的对象也不能被释放。
  2. public class Test {
  3.     static ArrayList<Person> list = new ArrayList<Person>();//list中引用的对象在应用整个生命周期中都不会被释放
  4.     public static void main(String[] args) {
  5.         for (int i = 1; i < 10; i++) {
  6.             Person person = new Person("" + i);
  7.             list.add(person);
  8.             person = null;//将变量person指向null,而不是指向堆内存中的Person对象;注意这时堆内存中的Person对象并没有被回收
  9.         }
  10.         for (Person person : list) {
  11.             System.out.println(person);//所有Person对象都没有被回收
  12.         }
  13.     }
  14. }
  15. class Person {
  16.     public String name;
  17.     public Person(String name) {
  18.         this.name = name;
  19.     }
  20.     @Override
  21.     public String toString() {
  22.         return name;
  23.     }
  24. }  
  25. 在这个例子中,如果仅仅释放引用本身(person = null),那么集合仍然引用该对象,所以这个对象对GC 来说是不可回收的。因此,如果对象加入到集合后,还必须从集合中删除,最简单的方法就是将集合对象设置为null

    • 监听器、回调、外部模块的引用
  26. 当注册的监听器不再使用后,如果没有被注销,那么很可能会发生内存泄露。
  27. public class Test {
  28.     public static void main(String[] args) {
  29.         B b = new B();
  30.         A a = new A();
  31.         b.register(a);
  32.         a = null;//虽然讲监听器设为null,但是监听器对象A并没有被回收,因为它被B引用了
  33.         b.show();//监听器工作了
  34.         b.unregister();//用完要注销掉
  35.     }
  36. }
  37. interface Listener {
  38.     public void listen();
  39. }
  40. class A implements Listener {
  41.     @Override
  42.     public void listen() {
  43.         System.out.println("监听器工作了");
  44.     }
  45. }
  46. class B {
  47.     Listener listener;
  48.     public void register(Listener listener) {//B持有了Listener的引用,除非在B内部将其设为null,否则listener将不会被回收
  49.         this.listener = listener;
  50.     }
  51.     public void unregister() {
  52.         listener = null;
  53.     }
  54.     public void show() {
  55.         if (listener != null) listener.listen();
  56.     }
  57. }  

    • 各种连接
  58. 比如数据库连接、网络连接(socket)和io流的连接,除非显式的调用了其close()方法将其连接关闭,否则是不会自动被GC回收的。
    • 内部类的引用
  59. 内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。
    • 单例模式
  60. 单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露。
  61.  

内存泄露 Memory Leaks的更多相关文章

  1. SQL Server 内存泄露(memory leak)——游标导致的内存问题

    原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...

  2. 内存泄漏 Memory Leaks 内存优化 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. 内存溢出(Oom)和内存泄露(Memory leak)

    1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...

  4. 利用linux的mtrace命令定位内存泄露(Memory Leak)

    一谈到内存泄露, 多数程序猿都闻之色变. 没错, 内存泄露非常easy引入. 但非常难定位.  以你我的手机为例(如果不常常关机). 如果每天泄露一些内存, 那么開始的一个星期, 你会发现手机好好的. ...

  5. 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别

    内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...

  6. 使用JProfiler分析定位java内存泄露memory leak

    使用jprofiler远程profile JBoss应用服务器 项目中发现JBoss出现内存泄露, 从2G一直涨到3.5G左右 开始考虑使用jmap dump出内存来, 在用jhap打开浏览器分析. ...

  7. python内存泄露memory leak排查记录

    问题描述 A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的. 针对每个集群,主线程会创建一个子线程,并由子线程去检测.子线程会频繁的创建和销毁. 上线以后,由于经常会有 ...

  8. Java 基础 - 内存泄露Memory leak & 内存溢出Out of memory

    内存泄露 & 内存溢出 关系 https://www.cnblogs.com/panxuejun/p/5883044.html 内存泄露的6种情况: https://blog.csdn.net ...

  9. 内存泄露 memory leak 的原因

    #include <iostream> using namespace std; void foo() { MyClass *x; x = new MyClass(); //指向的丢失了 ...

随机推荐

  1. js学习笔记之:时间(一)

    日期和时间是javaScript中常用的对象,可以通过此对象判断星期.生日.纪念日等,提高网站的人性化.下面将通过实例来介绍一下学习javaScript中有关时间和日期的知识点: (1)日期和时间函数 ...

  2. angularJS内置指令一览

    基础ng指令 ng-href ng-src ng-disabled ng-readonly ng-checked ng-selected ng-class ng-style ng-show ng-hi ...

  3. Python自动化运维之13、异常处理及反射(__import__,getattr,hasattr,setattr)

    一.异常处理 python异常: python的运行时错误称作异常 (1)语法错误:软件的结构上有错误而导致不能被解释器解释或不能被编译器编译 (2)逻辑错误:由于不完整或不合法的输入所致,也可能是逻 ...

  4. JS和正则表达式验证手机号码、邮箱等

    <-------------------------------------验证手机号码---------------------------------------------> fun ...

  5. Hibernate的查询语言之HQL(二)——Hibernate查询的from字句

    from 是最简单的HQL语句,也是最基本的HQL语句.from 关键字后紧跟持久化类的类名.例如: from Person 表明从Person持久化类中取出全部的实例. 大部分时候,推荐位该Pers ...

  6. 利用花生壳在自己电脑上建立外网可访问的svn

    下载花生壳并注册账号 2.花生壳会送你一个免费的二级域名 3.登陆到路由器界面192.168.0.1或者192.168.0.0进入动态dns选项输入你的花生壳账号密码 4.在路由器设置界面设置转发规则 ...

  7. hdu How many integers can you find

    题意:找出小于n是m个数每个数的倍数的数的个数. 思路:用二进制表示是那几个数的倍数. 二进制进行容斥,去掉小于0的数. #include <cstdio> #include <cs ...

  8. 用于 Visual Studio 和 ASP.NET 的 Web 应用程序项目部署常见问题

    https://msdn.microsoft.com/zh-cn/library/ee942158(v=vs.110).aspx#can_i_exclude_specific_files_or_fol ...

  9. 研究了下apache的漏洞CVE-2012-0053

    发一个大cookie过去,最新版本的,竟然显示了个\n 嘛意思 干嘛不直接删掉 Your browser sent a request that this server could not under ...

  10. <<开源硬件创客 15个酷应用玩转树莓派>>

    本书共分18章,前3章是本书的基础章节,主要介绍了树莓派的一些基本情况和基本操作,来让读者了解树莓派的前世今生,掌握树莓派基本的使用方法.第4~18章主要介绍15个以树莓派为载体的酷炫应用,大家可以按 ...