• 内存溢出


    1 内存溢出

    1.1 堆内存溢出outOfMemoryError:java heap space

    堆中的内存是用来生成对象实例和数组的,堆主要由新生代(eden区和两个survivor区组成)老年代、永久代。

    a、由内存泄露导致,内存溢出

    b、无法申请到足够的空间存放而导致的错误

    1.2 方法区溢出outOfMemoryError:PermGen space

    方法区主要存放的是类信息、常量、静态变量等如果应用会加载很多class或使用反射、glibc(需要更多的空间保存增强的类),就很可能出现PermGen space错误。

    1.3 线程栈溢出java.lang.StackOverflowError

    线程栈时线程独有的一块内存结构,所以线程栈发生问题必定是某个线程运行时产生的错误。

    一般线程栈溢出是由于死循环、递归太深或方法调用层级过多导致的,如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出上面异常。

    1.4 直接内存溢出

    DirectMemory可以通过-XX:MaxDirectMemorySize指定,如果不指定,默认与Java堆的最大值(-Xmx指定)一样。 

    NIO会使用到直接内存,你可以通过NIO来模拟,也直接使用UnSafe来分配直接内存。

    2 堆内存泄露原因和排查

    内存泄露指一些短生命周期的对象在完成自己职责后,本该被回收释放,却因为被一系列更长生命周期的对象引用,而不能被GC释放,我们称该对象被泄露了,随着泄露的积累,内存将被耗尽。

    2.1 内存溢出的场景

    1)长生命周期的对象持有短生命周期对象的引用

    这是内存泄露最常见的场景,也是代码设计中经常出现的问题。

    例如:在全局静态map中缓存局部变量,且没有清空操作,随着时间的推移,这个map会越来越大,造成内存泄露。

    2)修改hashset中对象的参数值,且参数是计算哈希值的字段

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

    3)机器的连接数和关闭时间设置

    长时间开启非常耗费资源的连接,也会造成内存泄露。

    2.2 解决方法

    1)jmap

    JDK自带的一个工具,是JVM Heap导出的必备工具。

    jmap -dump:format=b,file=xxx.bin pid pid是java程序pid

    此命令会将虚拟机heap镜像导成文件

    2) Eclipse安装MAT插件,并打开上一步通过jmap dump出来的heap.hprof内存快照文件进行分析

    然后GC roots引用链分析,查看是否存在无法自动回收的对象,如果对象都是有用的,说明没有内存泄露,检查虚拟机的堆参数(-Xmx-Xms

    内存泄露会导致内存溢出。。。

    3 申请空间不足的解决方法

    3.1 java.lang.OutOfMemoryError解决方法

    1) java.lang.OutOfMemoryError: PermGen space 持久代内存溢出

    修改参数

    JAVA_OPTS="-server -XX:PermSize=256M -XX:MaxPermSize=1024m

    2) java.lang.OutOfMemoryError: Java heap space 堆内存溢出

    Server端JVM建议-Xms设置与-Xmx相同,可以避免每次垃圾回收完成后JVM重新分配内存。

    -Xmn,整个堆大小=新生代大小 + 年老代大小 + 持久代大小。增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

    3) java.lang.StackOverflowError:栈溢出,通常是由于递归调用造成的

    -Xss128K(实际值需要经过严格的测试)。

    4) java.lang.OutOfMemoryError:直接内存溢出,通常是由于分配的直接内存太大

    4 避免内存泄露,需要注意

    1)尽早释放无用对象的引用 
    好的办法是使用临时变量的时候,让引用变量在推出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄漏。

    2)程序进行字符串处理时,尽量避免使用String,而应该使用StringBuffer。 
    因为String类是不可变的,每一个String对象都会独立占用内存一块区域。

    3)尽量少用静态变量 
    因为静态变量是全局的,存在方法区,GC不会回收。(用永久代实现的方法区,垃圾回收行为在这个区域是比较少出现的,垃圾回收器的主要目标是针对常量池和类型的卸载)

    4)避免集中创建对象,尤其是大对象,如果可以的话尽量使用流操作 
    JVM会突然需要大量neicun,这时会出发GC优化系统内存环境

    5)尽量运用对象池技术以提高系统性能 
    生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

    6)不要在经常调用的方法中创建对象,尤其忌讳在循环中创建对象 
    可以适当的使用hashtable,vector创建一组对象容器,然后从容器中去取这些对象,而不用每次new之后又丢弃。

    7)优化配置

  • 相关阅读:
    Google Earth 使用的经纬度格式及转换
    ADO.NET Entity Framework 一个简单数据绑定例子
    Oracle 异常 ORA01861: literal does not match format string(字符串格式不匹配)
    备份和还原 甲方 Oracle 数据库 问题一大堆
    使用 xsd.exe 命令工具 将 xsd架构 生成 类文件
    简单的源代码统计工具(统计源代码行数、工数、成本、质量指标统计)
    Google KML 起步教程笔记(二)高级 KML 文档与MIME 类型
    SQL Server 2008 中的空间数据存储
    PowerCmd 很好用的命令行工具,也许大家早就知道。
    Google Earth 本地地图缓存文件路径和KML文件路径
  • 原文地址:https://www.cnblogs.com/wuchanming/p/9097259.html
Copyright © 2020-2023  润新知