zoukankan      html  css  js  c++  java
  • OOM异常 Java内存溢出

    1.OutOfMemoryError 

    • 抛出异常后先确定是堆溢出还是栈溢出 
    1. 堆溢出:java.lang.OutOfMemoryError: Java heap space

      • 堆出现OOM(标志就是Java heap space)首先确认是内存溢出还是内存泄漏。常见的OOM就是堆溢出。
      • 内存泄漏: Memory Leak 申请到内存之后无法 释放 申请到的内存,造成这种情况的就是某个对象一直被引用这。
      • 内存溢出:Memory OverFlow :申请内存时没有足够的空间可以使用,抛出OOM。
      • 可以使用 Eclipse Memory Analyzer 或者 JProfiler(IDEA)分析内存是否泄漏
      1.  -Xms 设置初始堆的大小,设置为20MB -Xms20m
      2. -Xmx设置最大堆的大小
    2. 虚拟机栈溢出和本地方法栈溢出

      1. HotSpot 虚拟机并不区分虚拟机栈和本地方法栈他两适合在一起的所以 用来设置本地方法栈大小的-Xoos并没有什么效果。
      2. -Xss 设置栈容量大小
      3. 栈可以抛出2种异常
        •  StackOverflowError 线程请求的栈深度大于虚拟机所允许的最大深度。
        • OutOfMemoryError  扩展栈时无法申请到足够的内存,比较少见。
      4. 操作系统分配给每个进程的内存是有限的,如32位win给进程分配的是2G,栈内存 = 2GB - 堆Xmx - 方法区 MaxPermSize 
      5. 线程越多分配的栈内存就越少,每个线程分配的栈容量就越大线程就越少,容易把剩下的内存耗尽。
      6. jvm默认情况下栈深度平均在1000-2000间(栈帧个数即方法数量),如果不能更换更高位数的操作系统也不能减少线程数量,那么可以通过减少堆的最大容量让出一部分内存来给栈,避免栈内存溢出。
    3. 方法区和运行时常量池溢出

      1.  OutOfMemoryError:PermGen space 运行时常量池在方法区中他两都会抛出此异常。
      2. -XX:PermSize 方法区初始值大小
      3. -XX:MaxPermSize 方法区最大值 
      4. 由于1.8 去永久带 而加入了 Metaspace 元空间 所以上面的配置 1.8 开始就不能失效了
      5.  -XX:MetaspaceSize 元空间大小, -XX:MaxMetaspace元空间最大值。
    4. 本机直接内存溢出

      1. -XX: MaxDirectMemorySize 可以指定最大值,如果不指定默认和堆一样大。
      2. 由于直接内存不在堆里,它是供NIO使用的所以抛出OOM异常后通过jvm内存检测工具 在Heap Dump中没有明显错误,但是Dump文件很小就可以考虑直接内存溢出

    知识点:

    1. string.intern()是一个本地方法,它只 返回字符串常量池中唯一的那个string。
              String st1 = new StringBuilder("Mi").append("bloom").toString(); // 初始字符串常量池不存在组合的Mibloom  ,但存在了Mi和bloom.
              String st2 = new StringBuilder("ja").append("va").toString();// 初始字符串常量池存在java
              System.out.println(st1.intern() == st1);// 1.6为 false,1.7为true
              System.out.println(st2.intern() == st2);//始终为false, 常量池中存在java,因此 st2.intern()返回的是常量池中的,而st2是堆中的。
      1. 只要代码中直接出现的字符串就还会被放入常量池,但是组合生成的字符串不会被放入常量池的,如常量池中有Mi和bloom,但是没有Mibloom。
      2. 如果字符串常量池中已经包含了一个等于此string对象的符号,则string.intern()返回字符串常量池中的对象。
      3. 如果字符串常量池中没有,则将string加入字符串常量池并返回字符串常量池中的对象,此加入操作在jdk1.6 和1.7 中有所不同。
        1. 1.6中首次出现的string加入字符串常量池中的是直接复制到永久代中的字符串常量池中,所以地址会发生变化。
        2. 1.7开始 首次出现的string加入字符串常量池是复制string的引用到常量池中,所以地址不会发生变化。1.7开始 字符串常量池被移到了堆中。
    2. JVM 其他配置参数
      //常见配置汇总 
      //堆设置 
      -Xms:初始堆大小 
      -Xmx:最大堆大小 
      -XX:NewSize=n:设置年轻代大小 
      -XX:NewRatio=n:设置年轻代和年老代的比值.如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 
      -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值.注意Survivor区有两个.如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 
      -XX:MaxPermSize=n:设置持久代大小
      //收集器设置 
      -XX:+UseSerialGC:设置串行收集器 
      -XX:+UseParallelGC:设置并行收集器 
      -XX:+UseParalledlOldGC:设置并行年老代收集器 
      -XX:+UseConcMarkSweepGC:设置并发收集器
      //垃圾回收统计信息 
      -XX:+PrintGC 
      -XX:+PrintGCDetails 
      -XX:+PrintGCTimeStamps 
      -Xloggc:filename
      //并行收集器设置 
      -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数.并行收集//线程数. 
      -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间 
      -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比.公式为1/(1+n)
      //并发收集器设置 
      -XX:+CMSIncrementalMode:设置为增量模式.适用于单CPU情况. 
      -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数.并行收集线程数.
  • 相关阅读:
    一道小学数学题
    Ubuntu下使用git提交代码至GitHub
    C#几个小知识点
    C#中巧用#if DEBUG 进行调试
    使用 HPC Pack 为 Azure 中的 Windows HPC 工作负荷创建和管理群集的选项
    使用 Chef 自动执行 Azure 虚拟机部署
    在 Azure 中管理 Windows 虚拟机的可用性
    什么是 Azure 中的虚拟机规模集?
    从 Azure 下载 Windows VHD
    如何使用 Packer 在 Azure 中创建 Windows 虚拟机映像
  • 原文地址:https://www.cnblogs.com/mibloom/p/9244906.html
Copyright © 2011-2022 走看看