JVM(Java Virtual Machine) 即Java虚拟机,是一种用于计算设备的规范,用于运行Java程序编译后得到的字节码文件(Class文件)

一。JVM的内存区域

  1.程序计数器(Programing Counter Register)

    用于选取需要JVM执行的字节码指令,最简单的一种方法就是通过修改程序计数器的值来达到选取下一条需要执行的字节码指令的目的。

    如在多线程中CPU时间片切换时,可以通过线程私有的程序计数器来知道这次应当执行的是哪一条字节码指令。

    每个线程都会有一个独立的程序计数器,即这块内存是属于线程私有(或者说线程隔离)的。若是执行的是Native修饰的方法,则计数器值为空(Undefined)。

    此外,程序计数器所在的这块内存区域是唯一一个在JVM规范中没有任何OutOfMemoryError情况的区域

  2.Java虚拟机栈(也就是我们常说的栈内存)

    是线程私有的。每个方法在执行时都会创建一个栈帧(方法运行时的基础数据结构),用来存储局部变量、动态链接等。

    其中,局部变量表中存放:基本数据类型(boolean、byte、char、short、int、long、float、double)和对象引用类型(reference类型,如存储引用的变量?)

    在栈帧中,64位长度的long、double都会占用两个局部变量空间(Slot),其余数据类型均只占用1个Slot

    虚拟机栈会有两种异常情况:(1)线程请求的栈深度大于虚拟机所允许的深度,会抛出 StackOverflowError 异常。(2)当虚拟机栈可以动态扩展时,若扩展时无法申请到足够内存,则会抛出 OutOfMemoryError 异常

  3.Java堆(Java Heap)

    是所有线程共享的。同时也是JVM管理内存中最大的一块。JVM规范规定:Java堆可以处于物理上不连续的内存空间,只要逻辑上是连续的即可

    JVM规范同时规定:所有对象实例以及数组都要在堆上分配。即Java堆是用来存储对象实例和数组

    Java堆也是垃圾收集器管理的主要区域,因此有别名"GC堆"(Garbage Collection Heap)。

    当Java堆没有内存分配实例对象,且堆再也无法扩展时,会抛出 OutOfMemoryError 异常

  4.方法区

    是所有线程共享的。JVM规范中将方法区描述为堆的一个逻辑部分,但是却有一个别名叫 Non-Heap。

    方法区是用来存储JVM加载的类信息(即类的模板?)、常量、静态变量、即时编译器编译后的代码等数据的

    和Java堆一样不需要连续的内存,且可以选择固定大小或扩展,还可以选择不实现垃圾回收(该区域的回收效率低下,且条件苛刻;但这区域回收是必要的)。

    这区域的垃圾回收主要是针对常量池的垃圾回收和对类型的卸载。

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

    

  5.运行时常量池(Runtime Constant Pool)

    方法区的一部分。

    用于存放编译期生成的各种字面量和符号引用(如字符串常量);具备动态性,运行期间也可能将新的常量放入池中。

    String类的intern()方法  -----  去常量池中寻找当前字符串;若存在,返回找到与当前字符串值一样的字符串地址;若不存在,则将当前字符串存入常量池,再返回该地址。

    当常量池无法再申请到内存时,会抛出 OutOfMemoryError 异常

  总结:线程隔离的有:程序计数器,Java虚拟栈。虚拟栈有一个 StackOverflowError 异常

     线程共享的有:Java堆,方法区。方法区中有一个运行时常量池。

二。对象的创建

  1.虚拟机遇到一条 new 指令时,首先进行类加载检查(是否能在常量池中找到类的符号引用、符号代表的类是否已被加载、解析、初始化等)。

  2.通过类加载检查后,在Java堆中分配新内存。分配方式有:(1)指针碰撞:已用内存和空闲内存分置两边,中间设置一个指针作为分界点,每次通过移动指针来分配内存。(2)空闲列表:已使用内存和空闲内存相互交错,JVM维护一个列表,记录哪些内存块是可用的,分配时划分一块足够大的空间给对象。

  除了两种分配方式外,考虑到并发情况下的线程安全问题,提出了两种解决方案:

   (1)同步处理

   (2)本地线程分配缓冲(Thread Local Allocation Buffer, TLAB) : 每个线程在Java堆中预先分配一小块内存,当某线程的TLAB用完后再分配新的TLAB时,才需要同步锁定  

  3.内存分配完成后,JVM将分配到的内存空间初始化为零值。--- 以保证对象的实例字段可以不赋初始值就能直接使用(这一块没弄懂)

  4.对对象进行必要的设置。如对象头中设置对象的哈希码、对象的GC分代年龄、对象是哪个类的实例的标志等

三。对象的内存布局

  对象在内存中布局可以分为三块

  1.对象头:可分为两部分 :(1) 第一部分用于存储对象自身的运行数据。如哈希码、GC分代年龄、锁状态标志、线程持有的锁等。(2) 第二部分是类型指针,即对象指向它的类元数据的指针。JVM可通过这个指针确定对象是哪个类的实例;但并不是每个JVM都会在对象数据上保留类型指针,因为还有其他方法可以查找对象的元数据。

  2.实例数据:对象真正存储的有效信息,即程序代码中定义的各种类型的字段。如父类继承的、子类重定义的等

  3.对齐填充:这部分不是必然存在的。仅仅起着占位符的作用。以HotSpot虚拟机为例,对象起始地址必须是8字节的整数倍,即对象大小必须是8字节的整数倍。而对象头部分正好是8字节,当实例数据部分没有对齐时,则需要通过对齐填充来补全。

  此外,对象的主流访问定位方式有两种:(1)使用句柄:优点:引用中存储的是稳定的句柄地址,句柄中存放对象实例数据指针和对象类型指针,当对象移动时(垃圾回收时的普遍行为),只需改变句柄中的实例数据指针。(2)直接指针:优点 -- 快,节省时间开销 -- 地址指向的一块内存中既有对象实例数据,也有对象类型数据指针。使用句柄访问时,会在Java堆中划分出一块内存出来作为 句柄池,即句柄池也在Java堆中。

    

深入理解Java虚拟机阅读心得(一)的更多相关文章

  1. 深入理解Java虚拟机阅读心得(二)

    垃圾收集 程序计数器.虚拟机栈.本地方法栈三个区域随线程而生,随线程而灭:这几个区域的内存分配和回收都具备稳定性,不需要过多的考虑回收的问题.而Java堆和方法区则不一样. Java堆中存储了几乎所有 ...

  2. 深入理解Java虚拟机阅读心得(三)

    Java中提倡的自动内存管理最终可以归结为自动化的解决两个问题: 给对象分配内存 回收分配给对象的内存 先说说回收这一方面的两个主要知识点 一.垃圾收集算法 1.标记-清理算法 首先标记出所有需要回收 ...

  3. 深入理解Java 虚拟机阅读笔记(一)

    1.程序计数器- 占用空间:较小 作用:字节码行号指示器 作用详情:指示指令执行,如(字节码的执行,分支,循环,跳转,异常处理,线程恢复) 特点:线程私有(每个计数器独立计算,上下文相互独立). 2. ...

  4. 深入理解Java虚拟机--阅读笔记二

    垃圾收集器与内存分配策略 一.判断对象是否已死 1.垃圾收集器在对堆进行回收前,要先判断对象是否已死.而判断的算法有引用计数算法和可达性分析算法: 2.引用计数算法是给对象添加引用计数器,有地方引用就 ...

  5. 深入理解Java虚拟机--阅读笔记一

    Java内存区域 一.java运行时数据区域 1. 程序计数器:程序计数器占据的内存空间较小,是当前运行线程执行的字节码的计数:分支.循环.跳转.异常处理.线程恢复等都要依赖技术器来对执行的字节码进行 ...

  6. 深入理解JAVA虚拟机阅读笔记4——虚拟机类加载机制

    虚拟机把描述类的Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 在Java语言中,类型的加载.连接和初始化过程都是 ...

  7. 深入理解JAVA虚拟机阅读笔记1——JAVA内存区域

    一.Java内存区域 1.程序计数器 线程私有. 当前线程所执行的字节码的行号指示器.由于JAVA是多线程的,因此每个线程都独立的程序计数器. 异常:没有规定任何OutOfMemeryError情况的 ...

  8. 深入理解java虚拟机阅读笔记(1)运行时数据区域

    java虚拟机所管理的内存区域主要分为方法区.堆:虚拟机栈.本地方法栈.程序计数器,如图: 1.程序计数器是当前线程所执行的字节码行号指示器,用以记录当前指令执行的位置.程序计数器是线程私有的,每个线 ...

  9. 深入理解JAVA虚拟机阅读笔记6——线程安全与锁优化

    线程安全:如果一个对象可以安全的被多个线程同时使用,那它就是线程安全的. 一.Java中的线程安全 1.不可变 不可变的对象一定是线程安全的.String.枚举类型.java.lang.Number的 ...

随机推荐

  1. mybatis批量更新报错badsql

    mybatis批量更新时语法写的都对,但是报错,需要在连接上面加上allowMultiQueries=true 示例:jdbc:MySQL://192.168.1.236:3306/test?useU ...

  2. opencv2.4.13+python2.7学习笔记--OpenCV中的图像处理--图像轮廓特征和几何矩

    阅读对象:对概率论中的期望有一点了解. 1.图像几何矩 1.1简述 图像的几何矩包括空间矩.中心矩和中心归一化矩.几何矩具有平移.旋转和尺度不变性,一般是用来做大粒度的区分,用来过滤显然不相关的图像. ...

  3. android踩坑日记1

    Android四大组件-活动.服务.广播.碎片 情况一 应用场景:定时从服务器获取数据,然后活动或者碎片中根据最新获得的数据,更新UI. 思考: 首先定时,想到定时器,推荐使用系统自带的AlertMa ...

  4. Python3--Numpy

    数组的形状是它有多少行和列,上面的数组有5行和5列,所以它的形状是(5,5). itemsize属性是每个项占用的字节数.这个数组的数据类型是int 64,一个int 64中有64位,一个字节中有8位 ...

  5. “PurMVC”在Unity中的应用

    序章: 这是"游戏设计进阶技巧篇"内容,游戏中不使用如下技巧也可以正常运行,但是有了它以后可以增加项目的可读性,使功能”模块化“,”可视化“,”装逼化“(慢慢的恶意>,> ...

  6. Android开发者的Anko使用指南(四)之Layouts

    为什么不使用xml绘制Andoird的UI? 类型不安全 非空不安全 xml迫使你在很多布局中写很多相同的代码 设备在解析xml时会耗费更多的cpu运行时间和电池 最重要的时,它允许任何代码重用 简单 ...

  7. mysql中删除重复记录,只保留一条

    表结构如下: mysql> desc test1; +--------------+------------------+------+-----+---------+------------- ...

  8. CENTOS7常用的基础命令集合(一)

    目录(?)[-] CentOS7 常用命令集合 常用命令 文件与目录操作 查看文件内容 文本内容处理 查询操作 压缩解压 yum安装器 网络相关 系统相关 系统服务启动相关 防火墙相关 RPM包管理 ...

  9. 我所理解的Android组件化之通信机制

    之前写过一篇关于Android组件化的文章,<Android组件化框架设计与实践>,之前没看过的小伙伴可以先点击阅读.那篇文章是从实战中进行总结得来,是公司的一个真实项目进行组件化架构改造 ...

  10. Dubbo 源码分析 - 自适应拓展原理

    1.原理 我在上一篇文章中分析了 Dubbo 的 SPI 机制,Dubbo SPI 是 Dubbo 框架的核心.Dubbo 中的很多拓展都是通过 SPI 机制进行加载的,比如 Protocol.Clu ...