• JVM系列之一:内存区域和内存溢出


    1. 内存区域

     如下图为JVM的运行时数据区,我们常说的堆指的Java堆、栈指的是虚拟机栈;

     其中方法区和堆属于线程共享区;虚拟机栈、本地方法栈、PC属于线程独占区;

    1.1 程序计数器

     程序计数器是当前线程所执行字节码的行号指示器,记录字节码指令地址,来标识程序执行的顺序;

     在多线程中,为了保证线程切换后能恢复到正确的执行位置,每条线程都要有一个独立的程序计数器,因此它位于线程独占区

     程序计数器所在的区域是唯一一个没有OutOfMemortError情况的区域,因为程序员不需要擦去操作程序计数器;

    1.2 虚拟机栈

     1. 虚拟机栈描述的是Java方法的内存模型,它也是线程私有的,和线程的生命周期一样,每个方法在执行的时候,都会创建一个栈帧记录一些列信息

     2. 虚拟机栈不可以扩展:如果线程请求的栈深度大于JVM所允许的深度,将会抛出StackOverflowError异常

     3. 虚拟机栈可以扩展(大部门JVM都可以扩展):如果扩展时无法申请到足够的内存,抛出OutOfMemortError异常,栈大小可以通过-Xss指定

    1.3 Java堆

     1. 堆是JVM管理内存中最大的一块区域,被所有线程共享,这是多线程同步机制的原因

     2. 堆唯一的目的就是存放实例对象,所有的对象实例都在堆里分配

     3. 堆是垃圾收集器管理的主要区域,因此又被称为"GC堆"

     4. 堆可以处于物理上不连续的内存空间,只要逻辑上连续即可,像磁盘空间一样

     5. 堆可以固定,也可以扩展,通过-Xmx、-Xms控制堆最大、最小内存大小

      1.3.1 新生代/老年代

     1. 堆可以分为新生代和老年代,新生代分为Eden区、From Survivor空间、To Survivor空间

     2. 配置新生代和老年代在堆结构的占比

    • 默认-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的1/3
    • 可以修改-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/5

     3. 现在的商业虚拟机(例如HotSpot)都采用[复制算法]回收新生代,在HotSpot中,三个空间所占的比例是8:1:1,可以通过选项 -XX:SurvivorRatio=8

     4. 几乎所有的Java对象都是在Eden区被new出来的;98%的对象都销毁在了新生区

     5. 可以使用选项-Xmn设置新生代最大内存大小

      1.3.2 对象创建过程

     JVM创建对象(限于普通Java对象,不包括数组和Class对象)要面临4个问题:

     1. 怎么分配内存

    • JVM遇到一个new指令时,首先会检查常量池中是否有引用,如果没有,则为新对象分配内存
    • new创建的对象放在伊甸园区
    • 内存分配方式有“指针碰撞”和“空闲列表”两种,具体和JVM采用的收集器有关

     2. 怎么保证线程安全(修改指针指向的时候)

    • CAS+失败重试保证操作原则性
    • 本地线程分配缓冲方式(TLAB)可以通过-XX:+UseTLAB、-XX:-UseTLAB参数设置开启、关闭状态

     3. 怎么初始化对象

    • JVM要知道对象是哪个类的实例、如何找到类的元数据信息、对象的哈希码、对象的GC分代年龄等
    • 上述这些信息都存在对象头中

    4. 执行初始化方法

    1.3.3 对象分配过程

     1.new的对象先放伊甸园区。此区有大小限制。

    2.当伊甸园的空间填满时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。再加载新的对象放到伊甸园区

    3.然后将伊甸园中的剩余的幸存对象移动到幸存者0区。

    4.如果再次触发垃圾回收,此时上次幸存下来的放到幸存者0区的,如果没有回收,就会放到幸存者1区。

    5.如果再次经历垃圾回收,此时会重新放回幸存者0区,接着再去幸存者1区。

    6.啥时候能去养老区呢?可以设置次数。默认是15次。·可以设置参数:-XX:MaxTenuringThreshold=进行设置。

    7.在养老区,相对悠闲。当老年区内存不足时,再次触发GC:Major GC,进行养老区的内存清理。

    8.若养老区执行了Major GC之后发现依然无法进行对象的保存,就会产生OOM异常

  • 相关阅读:
    查找代码中的中文
    C# 清除cookies
    C# 32位程序在64位系统下注册表操作
    C# 32位程序在64位系统下运行中解决重定向问题
    C# 把一个文件夹下所有文件删除
    C# 把一个文件夹下所有文件复制到另一个文件夹下
    chromium浏览器开发系列第五篇:Debugging with WinDBG
    chromium浏览器开发系列第四篇:如何调试最新chromium源码
    chromium浏览器开发系列第三篇:chromium源码目录结构
    chromium浏览器高级开发系列第二篇:如何编译最新chromium源码
  • 原文地址:https://www.cnblogs.com/oxygenG/p/13484173.html
Copyright © 2020-2023  润新知