java学习-jvm-内存分配

  • 参考文章 
  • java内存结构
    • 堆(heap)
      • 内存中共享的运行时数据区域,用于存储实例化的java对象,当jvm启动时,该区域会被实例化
      • 在当前区域中只会存在java class对象以及数组数据,对于堆的空间大小可以通过启动参数 设置实现固定或动态
      • Jvm提供初始化和修改堆空间大小的用户控制;当 new 关键字在使用时,实例化的对象会被存放在堆空间中,但对于当前的对象的引用数据,会被存储在栈中
      • 每个jvm有且仅有一个heap区域
      • 对于 heap区域gc是强制的
      • Heap实际是由 eden + survivor(0/1) + oldGeneration 
    • 方法区(method area):实际也是属于heap的
      • 属于heap中的逻辑区域,在jvm启动时创建
      • 为class 结构/方法数据/构造器字段数据 分配的内存区域,空间大小也可以是固定或动态的;
      • 可以固定大小或动态扩容, 无需是连续的内存空间
      • 虽然 method area 属于 heap,但对于当前区域gc并非是强制的
      • 对于 run-time constant pool 是属于 method-area:主要是存储 编译时常量数据(字符串和数字)以及运行时的方法以及字段引用
    • 栈(stack)
      • 在线程创建时,栈也会随之创建,栈是属于线程的私有区域;当方法存在返回值和动态链接库,被用来存储数据和部分结果
      • 栈空间可以是固定的或动态的,也可以通过java代码在创建线程时来指定栈空间大小
      • 栈的内存空间无需是连续内存
      • 编程语言中的栈定义
        • 对于调用栈也可以称为栈,调用者会将返回的地址压入栈中然后调用下一个执行,当他完成时,调用栈的结果有可能出栈也有可能入栈以及转移指定地址的控制权;如果调用其他的行为时,则会将返回的地址写入调用的栈中;对于程序的执行就是出栈和入栈的结果
        • 对于高级语言中,特殊点在于对于调用栈的操作是隐藏的,只会提供相关的操作方法,而不允许直接操作内存
      • java 中的栈
        • 每个jvm线程都会拥有一个私有的栈空间,在创建线程时同步创建当前线程的栈空间;
        • jvm栈中存储的是帧(数据句柄)
        • jvm栈和c的栈一致,都是存储方法局部变量和运行时结果;
        • 由于jvm中栈空间绝对不会被直接操作;堆分配栈帧
        • jvm栈的空间不需要是连续内存
    • 本地方法栈(native method stack)
      • 也可以成为C语言栈,native method并不是由java代码生成,其内存只和线程关联,在线程创建时会分配内存, 也可以固定大小或动态
    • program counter registers
      • 每个执行特殊方法任务的jvm线程都会存在一个 程序计数器寄存器相关联;对于存在程序计数器的非native方法会存储有效的JVM指令地址,而 对于native方法中,该程序计数器的值时未定义的;
      • 在一些特殊的平台中,程序计数器寄存器支持存储返回数据的内存地址或一个 native 指针
    • 非堆(non-heap)
      • Metaspace : 元数据 ,一般包含一些class 数据
      • code cache: 
        • 对于code cache首先需要了解 java编译过程,以及jit
        • 对于一个java代码的执行过程; 首先 前端编译(javac): .java -> .class ;对于.class的执行并不能直接被cpu识别;
        • 此时就引出了后端编译器(执行 class 数据) 
        • 对于编译后的机器码数据,此时就会存储在codecache区域; 但在该区域不止包含jit编译后的机器码,也包含 jni (native)代码
  • 原生类型数据存储
    • 对于 编译时初始化的原生数据(int等),会在编译时存放到run-time constant pool中;
    • 对于方法参数中的原生数据是该方法执行时压入栈中的;
    • 对于类的属性,会在当前类实例化时直接存放在当前对象实例所在的堆区域 

      

public class JVMPrimaryDataDemo {
    // 对于当前常量数据,在类加载期间时将class文件转为Class对象后,初始化时会将当前数据存放到run-time constant pool 区域
    public static final int CONSTANT_COMPILER_DATA = 1;
    public int j = 4; // 对于该字段的数据是存放在构造方法中的;是存在于实例化对象中(堆)

    public static void main(String[] args) {
        // 而对于方法中的数据在运行时会被直接加载到栈中
        int i = 3; // 该数字在编译后会被翻译为 iconst_数值
    }
    /**
     * 对 编译后的class文件 使用javap -v 解析
     * // 常量池 == run-time constants pool
     * Constant pool:
     *    #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
     *    #2 = Class              #4             // java/lang/Object
     *    #3 = NameAndType        #5:#6          // "<init>":()V
     *    #4 = Utf8               java/lang/Object
     *    #5 = Utf8               <init>
     *    #6 = Utf8               ()V
     *    #7 = Class              #8             // com/xing/level/JVMPrimaryDataDemo
     *    #8 = Utf8               com/xing/level/JVMPrimaryDataDemo
     *    #9 = Utf8               CONSTANT_COMPILER_DATA // 字段名
     *   #10 = Utf8               I
     *   #11 = Utf8               ConstantValue
     *   #12 = Integer            1 // 声明的常量数据
     *   #13 = Utf8               Code
     *   #14 = Utf8               LineNumberTable
     *   #15 = Utf8               LocalVariableTable
     *   #16 = Utf8               this // 当前对象引用
     *   #17 = Utf8               Lcom/xing/level/JVMPrimaryDataDemo;
     *   #18 = Utf8               main // 方法名
     *   #19 = Utf8               ([Ljava/lang/String;)V
     *   #20 = Utf8               args // 参数名
     *   #21 = Utf8               [Ljava/lang/String;
     *   #22 = Utf8               i // 局部变量名
     *   #23 = Utf8               SourceFile
     *   #24 = Utf8               JVMPrimaryDataDemo.java
     */
}

 

posted @ 2020-10-20 18:26  郭星  阅读(141)  评论(0)    收藏  举报