JVM应该可以算Java中最为核心的部分了,其中开箱即用的内存管理又是JVM中的核心组成部分。我们都知道JVM的内存管理具有垃圾回收功能(Java Garbage Collector),编码时只需要new而无需主动的释放(类似于C++中的delete操作),所以Java中比较少出现内存泄露的情况。比较少出现,并不一定就不会出现,那么Java程序在什么时候会出现内存泄露呢?出现内存泄露该如何排查呢?

Java程序为什么会有内存泄露

什么是内存泄露呢?内存泄露可以定义为:当一个对象已经不再被应用程序使用以后,它所占用的内存没有得到及时的释放,导致内存使用量随着时间的推移不断的增加,最终导致应用程序崩溃的现象(Java中会在new新对象的时候抛出OutOfMemoryError)。

对于Java程序而言,当一个Object已经不会被程序所使用,但是它还被其它对象所引用,从而导致GC的时候无法被回收,从而导致内存泄露。

下图比较直观的展示了Java内存泄露发生的情形:

从上图我们可以把对象分为两大类:被引用的和不被引用的。垃圾回收的时候不释放那些不被引用的对象,被引用的对象则不会被释放,即便是这些对象后续一直都没有被用过。

定位Java内存泄露是比较麻烦的事情,需要使用到JVM提供的多种工具来进行内存分析,并且往往还需要结合代码进行分析。

Java堆内存泄露

首先我们来看看Java程序中最为常见的堆内存泄露。

如果想要直观的模拟出堆内存泄露,我们需要设置一一个较小的堆大小(内存泄露是独立存在的,和对内存大小无关,不过较小的堆内存大小可以更直观的观察到内存泄露)。

我们可以通过如下两个启动参数设置对内存大小:

通过静态变量来演示内存泄露

首先我们通过如下的代码来看看看看正常Java代码运行时的内存变化情况:

启动参数:-Xms20m -Xmx20m

运行是的内存变化图:

在我们的代码中我们每秒调用一次test方法,这个方法中会往list中添加数据,但是在方法返回之后这些数据就处于无引用状态了(并不一定会立马进行GC),我们每10秒调用一次System.gc()(full GC)。从内存监控图上能够直观的观察到堆内存的使用变化曲线。

接下来我们对上面的代码做一下修改:

静态变量保存了过多不在使用的对象引用导致的内存泄露是我们编码过程中最为常见的一种内存泄露方式。下面的代码就演示了这个情况:

为了更加直观的观察内存变化,我稍微调整了一下每次插入的数据个数,启动参数仍旧和上面一下。这个时候我们能够得到如下图所示的内存变化曲线:

从曲线中我们可以发现,堆内存使用量一直在增加,并没有和前一个示例一样在full GC后释放没有使用的堆内存,每次调用test方法后添加到list中的对象都会被list所引用,所以GC是不会收集并释放这些内存的。

如何定位和解决内存泄漏

Java的内存泄漏定位一般是比较困难的,需要使用到很多的实践经验和调试技巧。下面是一些比较通用的方法:

  1. 可以添加-verbose:gc启动参数来输出Java程序的GC日志。通过分析这些日志,可以知道每次GC后内存是否有增加,如果在缓慢的增加的那,那就有可能是内存泄漏了(当然也需要结合当前的负载)。如果无法添加这个启动参数,也可以使用jstat来查看实时的gc日志。如果条件允许的话可以考虑使用jvisualvm图形化的观察,不过线上的话一般没这个条件。
  2. 当通过dump出堆内存,然后使用jvisualvm查看分析,一般能够分析出内存中大量存在的对象以及它的类型等。我们可以通过添加-XX:+HeapDumpOnOutOfMemoryError启动参数来自动保存发生OOM时的内存dump。
  3. 当确定出大对象,或者大量存在的实例类型以后,我们就需要去review代码,从实际的代码入手来定位到真正发生泄漏的代码。

会不会导致内存泄漏_Java内存泄漏!为什么会泄漏?如何泄漏?怎么定位?相关推荐

  1. java 内存溢出和内存泄漏_JAVA内存泄漏和内存溢出的区别

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

  2. java io内存泄露_java内存泄露和OutOfMemory

    1.内存泄露: Java的内存泄漏是指某些对象不再被应用程序使用,而垃圾收集器(Garbage Collector)却没能识别它们是"不再使用的",所以没有对这些对象进行回收,或者 ...

  3. java堆内存 数据结构_JAVA内存区域

    首先解释下内存溢出和内存泄露之间的区别,为后面的学习做些铺垫: 1.内存溢出和内存泄露的区别和联系 内存溢出 out of memory:是指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你 ...

  4. java 解决内存泄露_Java内存泄露的理解与解决

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

  5. java查看内存泄露_Java内存泄露如何排查

    Java内存泄露是常常出现的问题,Java攀登网进行了该问题的整理,具体的如下所示: 1.2 内存泄露Memory Leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内 存泄露危害可以忽略 ...

  6. JAVA 继承内存模型_Java内存模型

    JVM的组成 类加载器(classloader) 执行引擎(execution engine) 运行时数据区域(runtime data area) 对于Java程序员来说,在虚拟机自动内存管理机制下 ...

  7. java内存规范_Java内存模型-jsr133规范介绍

    最近在看<深入理解Java虚拟机:JVM高级特性与最佳实践>讲到了线程相关的细节知识,里面讲述了关于java内存模型,也就是jsr 133定义的规范. 系统的看了jsr 133规范的前面几 ...

  8. java 内存溢出 内存泄露_java 内存泄露、内存溢出、内存不足

    内存泄露 什么是内存泄露? 在维基百科上的定义如图: 中文意思就是一个对象在内存中,而程序无法获取此对象,于是不能释放该对象所占用的内存. 百度百科上的定义如图: OWASP上的定义: 开发者无法释放 ...

  9. java 内存指针_java内存模型详解

    借用一句话:Java与C++之间有一堵内存动态分配和垃圾收集技术围成的高墙,墙外面的人想进来,墙里面的人却想出去. 一.我们为什么要了解JAVA内存 因为虚拟机帮我们JAVA程序员管理着内存,我们在n ...

  10. java 内存 回收_java内存回收

    一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此.所以,垃圾回收是必须的. 二. ...

最新文章

  1. 云原生应用的10大关键属性
  2. 使用ADO.NET直接连接Geodatabase
  3. 计算机在轻化工程中的应用,计算机在基础化学实验当中的应用
  4. 设计模式之 - 简单工厂模式
  5. emlog和typecho文章采集插件 简数第三方数据采集
  6. 业务异常 java_java – 具有业务异常的Hystrix断路器
  7. c语言kmeans算法具体步骤,k-均值聚类算法c语言版
  8. Redis 高级教程 Redis 安全(2)
  9. Json文件转Map(二)之解析节点
  10. pycharm pip安装_Python从入门到大师教程 | 一、搭建Python环境和安装Pycharm
  11. 科创板开市暴涨,详解25家企业的“造富”能力
  12. 神经元模型图手工制作,神经元模型图手工模型
  13. jcabanillas/yii2-inspinia-asset composert 安装失败
  14. 本地音乐播放器+android8.1,APlayer v1.5.6.8-15681 安卓本地音乐播放器 | 智享阁
  15. 区分 Linux 的硬链接与软链接
  16. Qt实现 文件比较工具
  17. vmware workstation 16 安装centos7 全记录(文字版)
  18. 一个视频分割为多个视频片段
  19. 重启MySQL报Unit mysqld.service could not be
  20. 初次使用Pikachu漏洞平台进行测试实验

热门文章

  1. poj 1836 Alignment
  2. 函数式编程的Java编码实践:利用惰性写出高性能且抽象的代码
  3. 「技术人生」第6篇:技术同学应该如何理解业务?
  4. 为什么Spring仍然会是云原生时代最佳平台之一?
  5. 新一代高效Git协同模型AGit-Flow详解
  6. 基于MaxCompute 衣二三帮助客户找到合适自己的衣服
  7. 万字长文丨1分36秒,100亿,支付宝技术双11答卷:没有不可能
  8. Quorum 和唱票那回事
  9. Java全能手册火了!Redis/Nginx/Dubbo/Spring全家桶啥都有!
  10. 我最喜欢的云 IDE 推荐!