zoukankan      html  css  js  c++  java
  • JVM 系列(二)内存模型

    02 JVM 系列(二)内存模型

    JVM 内存模型

    一、JVM 内存组成

    (1) PC 寄存器(线程私有)

    Java 虚拟机会为每个线程创建 PC 寄存器,在任意时刻,一个 java 线程总是在执行一个方法,这个方法被称为当前方法。

    如果当前方法不是本地方法,PC 寄存器就会执行当前正在被执行的指令,如果是本地方法,则 PC 寄存器值为 undefined,寄存器存放如当前执行环境指针、程序计数器、操作栈指针、计算的变量指针等信息。

    这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域。

    (2) Java 虚拟机栈(线程私有)

    每个方法在执行的时候会创建一个栈帧,存储了局部变量表,操作数栈,动态连接,方法返回地址等。每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。通常所说的栈,一般是指虚拟机栈中的局部变量表部分。局部变量表所需的内存在编译期间完成分配。

    如果线程请求的栈深度大于虚拟机所允许的深度,则 StackOverflowError。如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则 OutOfMemoryError。

    (3) 本地方法栈(线程私有)

    本地方法栈和 Java 栈非常类似,最大不同为本地方法栈用于本地方法调用。Java 虚拟机允许 Java 直接调用本地方法(通常使用C编写)。

    也会抛出 StackOverflowError 和 OutOfMemoryError。

    (4) Java 堆(线程共享)

    Java 虚拟机启动的时候建立 Java 堆,它是 Java 程序最主要的内存工作区域,几乎所有的对象实例都存放到 Java 堆中,堆空间是所有线
    被所有线程共享的。堆可以按照可扩展来实现:-Xmx(最大内存) 和 -Xms(初始化内存)

    当堆中没有内存可以分配给实例,也无法再扩展时,则抛出 OutOfMemoryError 异常。

    (5) 方法区(线程共享)

    用于存储已被虚拟机加载的类信息,常量,静态变量等。这个区域的内存回收目标主要针对常量池的回收和对类型的卸载。

    当方法区无法满足内存分配需求时,则抛出 OutOfMemoryError 异常。

    JDK1.7 中,已经把放在永久代的字符串常量池移到堆中。JDK1.8 撤销永久代,引入元空间。

    (6) 运行时常量池

    是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。当常量池无法再申请到内存时,则抛出 OutOfMemoryError 异常。

    (7) 直接内存

    Java 的 NIO 库允许 Java 程序使用直接内而提高性能,通红接内存速度会优于 java 堆。读写频繁的场合可能会考虑使用。

    直接内存不是运行时数据区的一部分,但也可能抛出 OutOfMemoryError 异常。

    总结:

    名称 特征 作用 配置 异常
    栈区 线程私有,使用一段连续的内存空间 存放局部变量表、操作栈、动态链接、方法出口 -Xss StackOverflowError OutOfMemoryError
    线程共享,生命周期与虚拟机相同 保存对象实例 -Xms -Xmx -Xmn OutOfMemoryError
    程序计数器 线程私有、占用内存小 字节码行号
    方法区 线程共享 存储类加载信息、常量、静态变量等 -XX:PermSize -XX:MaxPermSize OutOfMemoryError

    二、java 堆和 GC

    java 堆是和 java 应用程序关系最密切的内存空间,几乎所有的对象都存放在其中,并且 java 堆完全是自动化管理的,通过垃圾回收机制,垃圾对象会自动清理,不需要显示地释放。 Java 中的堆也是 GC 收集垃圾的主要区域。

    Java 堆结构

    根据垃圾回收机制不同,其中堆有可能拥有不同的结构:

    1. java 堆分为新生代和老年代。新生代存放新生的对象或者年龄不大的对象,老年代则存放老年对象。
    2. 堆大小 = 新生代 + 老年代。其中,堆的大小可以通过参数 –Xms、-Xmx 来指定。新生代与老年代的比例通过参数 –XX:NewRatio 来指定。
    3. 新生代分为 eden 区、s0 区、s1 区,s0 和 s1 也被称为 from 和 to 区域,他们是两块大小相等并且可以互换角色的空间。Edem与from的比例通过参数 –XX:SurvivorRatio 来指定。
    4. Minor GC 采用的是复制算法,将还存活的对象从 s0 拷贝到 s1 区。
    5. 绝大多数情况下,对象首先分配在 eden 区,在一次新生代回收后,如果对象还存活,则会进入 s0 或者 s1 区,之后每经过一次新生代向收,如果对象存活则它的年龄就加 1。

    三、参数配置

    参数 说明
    -Xms 初始堆大小。如:-Xms256m
    -Xmx 最大堆大小。如:-Xmx512m
    -Xmn 新生代大小。通常为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。实际可用空间为 = Eden + 1 个 Survivor,即 90%
    -Xss JDK1.5+ 每个线程堆栈大小为 1M,一般来说如果栈不是很深的话, 1M 是绝对够用了的。
    -XX:NewRatio 新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3
    -XX:SurvivorRatio 新生代中 Eden 与 Survivor 的比值。默认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10
    -XX:PermSize 永久代(方法区)的初始大小
    -XX:MaxPermSize 永久代(方法区)的最大值
    -XX:+PrintGCDetails 打印 GC 信息
    -XX:+HeapDumpOnOutOfMemoryError 让虚拟机在发生内存溢出时 Dump 出当前的内存堆转储快照,以便分析用

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    Safe Path(bfs+一维数组存图)
    一维树状数组入门
    Ancient Go(简单DFS)
    Sudoku(简单DFS)
    Strategic game(树形DP入门)
    多线程源码分析
    Navicat premium12的破解方法,无需注册码
    MySQL和Oracle的区别
    java Web项目中什么场景中会用到java多线程?
    TCP协议三次握手、四次断开 过程分析
  • 原文地址:https://www.cnblogs.com/binarylei/p/9249563.html
Copyright © 2011-2022 走看看