zoukankan      html  css  js  c++  java
  • 5-运行时数据区

    一.运行时数据区

    一个class文件被classloader加载到内存,经过load/link/initialize三步之后,然后交给jvm的运行时引擎运行,运行的时候在内存里面是一个什么情况?

    根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域。

    程序计数器(Program Counter Register):是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。

    java虚拟机栈(JVM stacks): 线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表操作数栈动态连接方法出口等信息。

    本地方法栈(Native Method Stacks):与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地 (Native) 方法服务。

    Java堆(Java Heap):是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java 世界里“几乎”所有的对象实例都在这里分配内存。

    方法区(Method Area):是一种逻辑划分。与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息(类名、访问修饰符、字段描述、方法描述等)、常量池(静态常量在编译器存入class文件常量池)、静态变量、即时编译器编译后的代码缓存等数据。

    jdk1.8之前叫永久代(Perm Space)字符串常量位于Perm Space,FGC不会清理。

    jdk1.8之后叫元数据区域(Meta Space )包含类型信息/运行时常量池(run-time constant pool)。字符串常量位于堆,会触发FGC。

    直接内存(Direct Memory):jvm可以直接访问的内存(os管理的内存)。NIO,提高效率,实现zero copy。

    二.分析java虚拟机栈(JVM stacks)

    Frame(栈桢):用于存储局部变量表操作数栈动态连接方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

    局部变量表(local variables):存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、 int、 float、long、double)、对象引用。

    操作数栈(operand stacks)

    动态连接(dynamic linking):动态链接是一个将符号引用解析为直接引用的过程。java虚拟机执行字节码时,遇到一个操作码,操作码第一次使用一个指向另一类的符号引用,则虚拟机就必须解析这个符号引用。

    方法出口(return address): a() -> b(),方法a调用了方法b, b方法的返回值放在什么地方

    让我们从一个小demo分析一下jvm stacks是如何运作的。

    public class Test1 {
        public static void main(String[] args) {
            int i = 1;
            i = i++;
    //        i = ++i;
            System.out.println(i);
        }
    }
    

    输出:1

    我们来分析一下字节码:

    1. icons_1 把1压入操作数栈(栈顶为1)
    2. istore_1 把1出栈存储到局部变量表索引为1的位置(i此时为1,栈为空)
    3. iload_1 把局部变量表索引为1的值压入操作数栈(栈顶为1)
    4. iinc 1 by 1 把局部变量表索引为1的值加1(i此时为2)
    5. istore_1 操作数栈出栈将值赋给局部变量表索引为1的位置(i此时为1,栈为空)

    所以最终局部变量表索引为1位置(即i)的值为1。

    再来看看这个小demo

    public class Test1 {
        public static void main(String[] args) {
            int i = 1;
    //        i = i++;
            i = ++i;
            System.out.println(i);
        }
    }
    

    输出:2

    我们来分析一下字节码:

    1. icons_1 把1压入操作数栈
    2. istore_1 把1出栈存储到局部变量表索引为1的位置
    3. iinc 1 by 1 把局部变量表索引为1的值加1 (i此时为2)
    4. iload_1 把局部变量表索引为1的值压入操作数栈
    5. istore_1 操作数栈出栈将值赋给局部变量表索引为1的位置(i此时为2)

    所以最终局部变量表索引为1位置(即i)的值为2。

  • 相关阅读:
    时间差的计算
    时间差的计算第二篇
    并不能完全不编码完成Windows Service的安装和卸载
    今年是搜索引擎年吗?热!搜索引擎算法点击率火爆
    Virtual PC,我真的不敢用你!
    我理解的17种C#写的Hello World程序
    反搜索引擎
    如何保证Windows Serverice健壮长效运转?
    服务器是怎么做成的?
    超酷的超级DataGrid
  • 原文地址:https://www.cnblogs.com/tc971121/p/13442776.html
Copyright © 2011-2022 走看看