zoukankan      html  css  js  c++  java
  • java内存区域与内存溢出异常

    java内存区域与内存溢出异常

    运行时数据区

    程序计数器/PC寄存器

    • 当前线程所执行的字节码的行号指示器
    • 每条线程都是独立的,独立存储,线程私有内存
    • 当线程执行一个java方法时,记录正在执行的虚拟机字节码指令地址. 若为native方法,则为空
    • 唯一一个java虚拟机中没有规定OOM情况的区域

    虚拟机栈/方法栈

    • 每个方法在执行时都会创建一个栈帧用于存放局部变量表,操作数栈,动态链接,方法出口等信息.每一个方法从调用到完成对应这一个栈帧在虚拟机中的入栈到出栈

      • 局部变量表:存放编译期可知的基本类型,对象的引用(引用指针,对象句柄或其它与对象相关的位置信息 非对象本身),returnAddress类型(指向了一条字节码指令的地址)

    64位(long,double)会占用2个局部变量空间(slot),其余占用一个

    在方法运行时不会改变大小

    • 线程私有的,生命周期与线程保持一致
    • 常说的栈内存指的就是虚拟机栈
    • 异常信息:
      StackOverFlowError:线程请求的栈深度大于虚拟机允许的栈深度
      OutOfMemoryError:虚拟机可动态扩展,但扩展时无法申请到足够内存

    本地方法栈

    • 与虚拟机栈基本一致
      区别:
      仅保存Native方法信息

    java堆/GC堆

    • 存放对象实例

    • 被所有线程共享,虚拟机启动时创建

      • 共享总大小内存,对于每一个线程可能划分出私有的分配缓冲区
    • 垃圾管理器主要区域,所以也被称为GC堆

      • 因此分出年轻代(eden,survivor),老年代(old) 1:1:8
    • -Xms -Xmx

    • OOM

    方法区(Non-Heap)

    • 用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码

    • 所有线程共享

    • 在HotSpot也被称为永久代

      • 在JDK1.7版本的HotSpot中已将放在永久代的字符串常量池移出
    • 方法区可以不实现垃圾收集

    • OOM

    运行时常量池

    • 方法区 的一部分

    • 用于存放编译期生成的字面量,符号引用,直接引用,当类加载完毕后加入

    • 具备动态性,运行期间也可将新的常量放入池中, String.intern()

      • String.intern()

        • jDK1.6 会将实例复制到永久代,并返回这个复制的引用
        • JDK1.7 不在复制实例,仅在常量池中记录首次出现的实例引用
        • String str = "java";
          String str2 = new String("java");
          boolean flag = str == str2 ;
          flag 是false
          new String() 创建一个对象并在堆上,str2保存堆对象地址
          "java“str保存的是常量池中的java地址;
    • OOM

    直接内存

    • 不属于运行时数据区,也不是java虚拟机规范中定义的内存区域
    • OOM

    对象

    对象的创建

    • 1.类加载检查. 先查询参数是否在常量池中有一个类的符号引用, 检查这个符号引用代表的类是否已经被加载,解析 初始化过,如果没有 ,则需要进行相应的类加载过程

      1. 虚拟机分配内存,并初始化为0(不包含对象头)
      • 2.1 指针碰撞,要求java堆中内存绝对规整

      • 2.2 空闲列表

      • 2.3 线程安全问题

        • 2.3.1 采用CAS和失败重试机制保证更新的原子性
        • 2.3.2 本地线程分配缓冲(TLAB)
    • 3.虚拟机对对象进行必要设置,实例信息,元数据信息,对象hash码,GC分代信息等,这些信息在对象头中

    • 执行init方法 代码:P45

    对象的内存布局

    • 对象头

      • 运行时数据 Mark Word

        • HashCode,GC分代年龄,锁状态标示,线程持有的锁,偏向线程ID,偏向时间戳
        • 32位:对象处于未锁定状态 25bit HashCode 4bit 分代年龄 2bit 锁标志位 1bit 固定0
      • 类型指针

        • 对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象时那个类的实例
    • 实例数据

      • 存储对象的有效信息,定义的字段内容,受到java编写顺序和虚拟机分配策略参数影响
    • 对齐填充

      • 非必然存在,仅仅是占位符的作用

    对象的访问定位

    • 通过栈中的reference数据来操作堆中的具体对象

      • 直接指针 reference 中直接保存对象地址
        SUN HotSpot 采用直接指针

        • 实例数据
        • 类型数据指针
      • 使用句柄 reference中保存句柄地址

        • 在堆中维护一个句柄池

          • 实例数据指针
          • 类型数据指针

    OOM

    参数设置: -verbose:gc -Xms20M -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8

    • java堆溢出

      • java heap space 会有dump文件 ,通过分析dump文件确定是溢出还是泄漏

        • 泄漏: 查看GC roots 的引用链定位泄漏代码
        • 溢出:调整物理机内存大小,查看对象的生命周期是否过长,持有状态过长, 减少程序运行期间的内存消耗
    • 虚拟机栈和本地方法栈溢出

      • 单线程

        • 仅会抛出StackOverflowError
      • 大小: 操作系统分配进程内存2G(32位 win) - Xmx(最大堆容量) - MaxPermSize(方法区) 剩余部分可大致认为是其大小
        程序计数器忽略,忽略消耗

        • 所以当无法减少运行的线程数和无法换成64位机器时,可以考虑减少堆内存和方法区的内存大小来达到提升栈内存
    • 方法区和运行时常量池溢出

      • 动态生成大量的class时有可能发生,常见的有:动态生成大量JSP文件,基于OSGi的应用
    • 本机直接内存溢出

      • 通过-XX: MaxDirectMemorySize指定,默认与堆最大值一致(-Xmx)
      • Heap Dump 文件中不会看见明显的异常,若OOM后Dump文件很小,程序中直接或间接使用了NIO则可能出现

    高清思维导图版请关注公众号‘伊人网络’ 回复 ‘内存’ 即可领取

  • 相关阅读:
    scala简单的功能实现~weektwo
    linux中/dev/null与2>&1讲解
    scala简单的功能实现~weekone
    oracle之随机数
    oracle之percent_rank() over()函数和PERCENTILE_CONT() within group()over()函数详解
    awk编程的基本用法
    Django-路由系统
    selectors模块
    threading中定时器Timer方法
    HTML-W3school首页制作
  • 原文地址:https://www.cnblogs.com/diandiandian/p/13192369.html
Copyright © 2011-2022 走看看