zoukankan      html  css  js  c++  java
  • 什么是内存泄漏,为什么会导致内存溢出?

    工作一段时间后,会经常听到内存溢出,那内存溢出到底是哪里的内存溢出,是什么原因导致的,如何解决,今天就来深入了解一下.

    在java中,要了解内存,需要先清楚jvm内存模型,我们常说的java内存实际上就是指Runtime Data Area,分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分.这里不做具体介绍.

    1.常见的内存泄露

    (1)内存分配未成功,却使用了它
    (2)内存分配成功,但尚未初始化就引用它
    (3)内存分配成功且初始化,但操作越过了内存的边界
    (4)忘记释放内存,造成内存泄漏
    (5)释放了内存却继续使用它
    以发生的方式来分类:
    (1)常发性内存泄漏,发生内存泄漏的代码会被多次执行到,每次执行都会导致一块内存泄漏
    (2)偶发性内存泄漏
    (3)一次性内存泄漏,发送泄漏的代码只会被执行一次
    (4)隐式内存泄漏,程序在运行过程中不停地分配内存,但直到结束时才释放内存。

    2.为什么会导致内存溢出

    编写java程序最为方便的地方就是我们不需要管理内存的分配和释放,一切由jvm来进行处理,当java对象不再被应用时,等到堆内存不够用时,jvm会进行垃圾回收,清除这些对象占用的堆内存空间,如果对象一直被应用,jvm无法对其进行回收,创建新的对象时,无法从Heap中获取足够的内存分配给对象,这时候就会导致内存溢出。而出现内存泄露的地方,一般是不断的往容器中存放对象,而容器没有相应的大小限制或清除机制。容易导致内存溢出。

    3.如何发现内存泄漏
    可以直接使用VisualVM,已在JDK6.0 update 7 中自带,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈.

    如果要在服务器上使用Java VisualVM, 比如CentOS。那么就出现 WARNING: environment variable DISPLAY is not set,因为一般服务器都不会装X server。我们可以在远程机器上装一个X server,比如windwos上,那么就可以非常方便的查看服务器运行情况。
    如果有大量的FGC就要查询是否有内存泄漏的问题了,图中的FGC数量就比较大,并且执行时间较长,这样就会导致系统的响应时间较长,如果对jvm的内存设置较大,那么执行一次FGC的时间可能会更长。(直接运行linux上的jvisualvm,下载X-Manager,可以将视图展现在本地机器上。)

    从上图可以发现执行FGC的情况,下午3:10分之前是没有FGC的,之后出现大量的FGC。

    上图是jvm堆内存的使用情况,下午3:10分之前的内存回收还是比较合理,但是之后大量内存无法回收,最后导致内存越来越少,导致大量的full gc。

    4.如何定位内存泄漏

    1、查看Visual GC标签,内容如下,这是输出first的截图
                
    这是输出forth的截图:
    通过2张图对比发现:
    老生代一直在gc,当程序继续运行可以发现老生代gc还在继续:
    增加到了7次,但是老生代的内存并没有减少。说明存在无法被回收的对象,可能是内存泄漏了。
    如何分析是那个对象泄漏了呢?打开抽样器标签:点击后如下图:
    按照程序输出进行堆dump,当输出second时,dump一次,当输出forth时dump一次。
    进入最后dump出来的堆标签,点击类:
    点击右上角:“与另一个堆存储对比”。如图选择第一次导出的dump内容比较:
    比较结果如下:
    可以看出在两次间隔时间内TestMemory对象实例一直在增加并且多了,说明该对象引用的方法可能存在内存泄漏。
    如何查看对象引用关系呢?
    右键选择类TestMemory,选择“在实例视图中显示”,如下所示:
    左侧是创建的实例总数,右侧上部为该实例的结构,下面为引用说明,从图中可以看出在类CyclicDependencies里面被引用了,并且被HashMap引用。
    如此可以确定泄漏的位置,进而根据实际情况进行分析解决。
     


    
    
    
  • 相关阅读:
    使用shell从DB2数据库导出数据
    kettle插入/更新
    kettle删除资源库中的转换或者作业
    DB2中的转义字符
    Kettle行列转换
    Linux查看文件以及文件夹的大小
    Linux下如何查看JDK安装路径
    使用Linux调用资源库中的Job报错-ERROR: No repository provided, can't load job.
    通过shell脚本获取日期,并赋给变量
    批处理判断是否存在文件,存在则运行另外一个bat文件
  • 原文地址:https://www.cnblogs.com/iceggboom/p/13280244.html
Copyright © 2011-2022 走看看