zoukankan      html  css  js  c++  java
  • Jvm笔记-01-Java运行时数据区域与对象

    运行时数据区域

    1. 程序计数器 Program Counter Register

    通过改变计数器值选取下一条指令完成分支、循环、跳转、异常处理、线程恢复等基础功能。
    线程私有,互不影响。

    2. Java虚拟机栈 JVM Stacks

    线程私有,生命周期与线程相同。
    每个方法执行时创建栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等,方法调用与完成对应入栈和出栈。
    Java内存区粗略分为堆和栈,栈即虚拟机栈。
    配置 -Xss 参数设定栈帧大小

    3. 本地方法栈 Native Method Stack

    执行本地方法的栈。

    4. Java堆 Java Heap

    线程共享,虚拟机启动时创建,几乎所有对象在这里分配内存。
    Java堆分为新生代(EdenFrom SurvivorTo Survivor)和老年代。
    -Xms 最小值,-Xmx 最大值

    5. 方法区 Method Area

    线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。
    被成为永久代 Permanent Generation,配置 -XX:MaxPermSize 上限。

    6. 运行时常量池 Runtime Constant Pool

    运行时常量池是方法区中一部分,jdk8被放到 MetaSpace 空间。
    类的版本、字段、方法、接口等描述信息,还有常量池(Constant Pool Table ),存放编译期生成的各种字面量和符号引用。
    jdk7之前,字符串常量池在方法区中,使用 String.intern() 方法可将字符串放入。

    7. 直接内存 Direct Memory

    不是虚拟机运行时数据区的一部分,也可能OOM异常。
    jdk1.4加入NIO,是一种基于通道 Channel 和缓冲区 Buffer 的I/O方式,可以使用 Native 函数库直接分配对外内存,然后通过堆中 DirectByteBuffer 对象作为这块内存的引用进行操作,避免Java堆与Native堆中数据复制来提高效率。

    对象

    对象的创建

    1. 遇到new指令时,首先检查指令参数能否在常量池中定位到一个类的符号引用,并检查这个这个符号引用代表的类是否被加载、解析和初始化过。

    2. 如果没有,执行相应的类加载过程。

    3. 类加载通过后,虚拟机为新生对象分配内存。

       如何分配内存?
       对象所需内存大小在加载完成后便完全确定,所以将一块确定大小内存从Java堆中划分出来即可。  
       若内存规整,采用指针碰撞分配算法,将指针向空闲空间挪动。
       若非连续存放,须维护空闲列表,找到足够大空间划分。
       `Serial` 串行收集器、`ParNew` 多线程串行收集器等带 `Compact` 过程收集器,分配算法采用指针碰撞。
       `CMS` 这种基于 `Mark-Sweep` 算法,采用空闲列表。
      
    4. 内存分配完成后,将分配到的内存空间初始化为零值。

    5. 虚拟机对对象进行必要设置,该实例所属类、类的元数据信息、对象哈希姆、对象GC分代年龄信息等,存放在对象头中。

    6. 执行 <init> 构造方法,按照程序员的意愿进行初始化,对象引用入栈。

    对象的内存布局

    对象在内存中存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

    1. 对象头包括两部分信息

      第一部分是存储对象自身的运行时数据 Mark Word

       如哈希码、GC分代年龄、锁状态标识、线程持有锁、偏向线程ID、偏向时间戳等。
      

      另一部分是类型指针,即对象指向它的元数据的指针。

       虚拟机通过这个指针来确定该对象是那个类的实例。
      
    2. 实例数据

       对象真正存储的有效信息,即代码中定义的各类型字段内容。
      
    3. 对齐填充

       仅是占位符作用。
      

    对象的访问定位

    通过栈上的引用 reference 来操作堆上具体对象,主流的访问方式有使用句柄和直接指针两种。

    1. 句柄访问。

       Java堆中将划分出句柄池,'reference' 指向句柄地址,句柄中存放了对象实例数据与类型数据各自的具体地址信息。  
       优势:在对象被移动时只会改变句柄中实例数据指针,reference本身不需要修改。
      
    2. 直接指针访问。

       'reference' 直接存储对象地址,Java堆中对象布局中须防止访问类型数据信息。
       优势: 访问速度快,因节省了一次指针定位的时间开销。
       HotSpot使用直接指针进行对象访问。
  • 相关阅读:
    包和常用内置模块(二)
    常用内置模块(一)
    正则表达式和re模块
    迭代器和生成器
    函数(四)
    函数(三)闭包函数与装饰器
    Codeforces Round #539 (Div. 2) D 思维
    Codeforces Round #539 (Div. 2) 异或 + dp
    Codeforces Round #546 (Div. 2) E 推公式 + 线段树
    牛客练习赛42 C 反着计算贡献
  • 原文地址:https://www.cnblogs.com/hiqianqian/p/7403677.html
Copyright © 2011-2022 走看看