INTRO

  • 称为存储渗漏。
  • 严格来说,当对象不会被用到了,但Garbage Collector不能回收,称为内存泄露。
  • 很多情况是,由于使用不当,导致对象的生命周期变得很长,甚至导致Out of Memory,称为宽泛意义上的内存泄露

对象引用无法回收的情况

分类

  • 经常发生:泄露的代码会被多次执行
  • 偶尔发生:某些特定情况下才会发生
  • 一次性:代码只执行一次
  • 隐式泄露:一直占着内存不释放,直到执行结束

内存泄露与内存溢出的关系

  • 内存泄露最终会导致内存溢出

内存泄露的情况

  • 静态集合集
    • static 标记的 HashMap LinkedList
    • 生命周期与JVM一致
    • 在程序结束之前不能被释放
  • 长生命周期的对象,持有短生命周期对象的引用,导致短生命周期的对象无法被回收
  • 单例模式
    • 单例是指一个类只有一个实例化对象
    • 因此这个对象与类是相互绑定的关系
    • 是静态的
    • 生命周期与JVM一致
  • 内部类持有外部类
    • 内部类被长期引用
    • 内部类归属于外部类
    • 因此,即使外部类不再被使用,也不能被回收
  • 各种连接,数据库连接,网络连接,IO连接
    • 这些连接如果没有被关闭的话,垃圾回收器不会回收其对象
    • 数据库一般会维持一个大小恒定的连接池
  • 变量不合理的作用域
    • 变量的作用范围大于其使用范围
    • 导致某些不该存在的变量在内存中多存活一段时间
  • 改变哈希值
    • 一个对象被存储进HashSet中,不能修改参与哈希值计算的字段
    • 否则对象修改后的hash值,和set中的hash不一致
    • 使用当前对象去检索,在set中将检索不到
    • 因此,如果修改前的对象丢失,很容易造成HashSet中对象不能检索和删除
    • 造成内存泄露
  • 缓存泄露
    • 当你把对象放进缓存中时,很容易遗忘他
    • 可以使用WeakHashMap代替缓存
    • 当map中的key没有其他refernece时,会自动丢弃此key
  • 监听器和回调
    • 回调函数:主函数执行完,再执行穿参进来的回调函数
    • 回调函数如果没有被显示的取消,仍然会占用内存
    • 可以使用WeakHashMap存他的弱引用

如何定位内存泄露

  • 主要命令
    • jstack 生成虚拟机中所有线程的快照 一般用于CPU 100%
    • jmap 生成堆转储快照
      • jmap -dump:format=b, file={path}{pid}
      • 利用mat分析dump文件
      • mat Memory Analyzer Tool
  • JVM常用命令
    • jps
    • jstat
    • jinfo
    • jmap
    • jstack
    • jhat
  • JVM性能检测工具
    • Eclipse Memory Analyzer
    • JProfile
    • JProbe Profiler
    • JVisualVM
    • JConsole
    • Plumbr
  • 引用一个分析BLOG