深入理解Java虚拟机--阅读笔记一
Java内存区域
一、java运行时数据区域
1、 程序计数器:程序计数器占据的内存空间较小,是当前运行线程执行的字节码的计数;分支、循环、跳转、异常处理、线程恢复等都要依赖技术器来对执行的字节码进行执行位置的计算来实现的。程序计数器的内存空间是每条线程独有的,也称之为“线程私有”的内存;计数器记录的是正在运行的字节码指令的地址,而如果是Native方法(本地方法),则计数器的值为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
2、java虚拟机栈:java虚拟机栈也是线程私有的,它的生命周期与线程相同。每个方法在运行的时候都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法的调用,就对应着一个栈帧在虚拟机栈种从入栈到出栈的过程。局部变量表中存储了编译期可知的各种基本数据类型,(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型)和returnAddress类型。java虚拟机栈会抛出StackOverflowError异常和OutOfMemoryError异常。
3、本地方法栈:本地方法栈是本地方法的“java虚拟机栈”。
4、Java堆:Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”;根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,当前主流的虚拟机都是按照可扩展实现的(当然可以是固定的),通过-Xmx和-Xms控制。当没有内存可以完成对象的实例的分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
5、方法区:方法区也是被线程共享的,它存储的是:被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。
对于Java堆从内存回收的角度来看,Java堆可以分为新生代和和老年代;很多人愿意把方法区称为“永久代”(限于HotSpot虚拟机);根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
6、运行时常量池:时方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。因为运行期间也可能会因为String类的intern()方法来将新的常量放入池中,所以当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
二、对象的创建
1、 虚拟机遇到一条new的指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有就先进类的加载过程,在类加载完成后为新生对象分配内存。而分配内存的分配算法被受到收集器的算法的影响。在使用Serial、ParNew等带Compact过程(压缩)的收集器时,系统采用的分配算法是“指针碰撞”;而使用CMS这种基础MARK-Sweep算法(标记-清理算法)的收集器时,系统采用的分配算法是”空闲列表“;
2、虚拟机为保证线程安全的两种内存分配机制:第一种是对分配内存空间的动作进行同步处理--实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;另一种是采用本地线程分配缓冲(TLAB)。虚拟机在内存分配完成后把内存空间初始化为零值(不包括对象头),TLAB是分配的同时进行初始化。这样对象的初始值就不是空而是零,可以在不手动赋值的情况下进行调用。
三、对象的内存布局
1、对象在内存中存储的布局可以分为三个区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
2、对象头包括两部分:第一部分用于存储对象的运行时数据(如:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程的ID、偏向时间戳等);另一部分是类型指针,即指向其类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。java数组的记录长度的数据也会存在对象头中,虚拟机可以通过普通java对象的元数据信息确定java对象的大小。
3、实例数据就是类中定义的各个字段的实例数据。
4、对齐填充不是必然存在的,由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象示例数据部分没有对齐时,就需要通过对齐填充来补全。
四、对象的访问定位
1、访问对象有使用句柄和直接指针两种方式;都是通过存在Java虚拟机栈本地变量表中的reference指向Java堆来找到对象。
2、使用句柄的方式:通过reference来访问Java堆中专门划分出来的句柄池(这时reference中存储的就是对象的句柄的地址),而句柄池中的句柄包含了到对象示例数据的指针和到对象类型数据的指针;存放对象实例对象的实例池在Java堆中,对象类型数据在方法区。这种方法的好处就是在对象移动时(垃圾收集时经常移动对象)只需要改变句柄中的指向对象实例数据的指针。
3、使用直接指针访问,reference直接指向对象实例数据和到对象类型数据的指针。这种方式的好处就是更快,
深入理解Java虚拟机--阅读笔记一的更多相关文章
- 深入理解Java 虚拟机阅读笔记(一)
1.程序计数器- 占用空间:较小 作用:字节码行号指示器 作用详情:指示指令执行,如(字节码的执行,分支,循环,跳转,异常处理,线程恢复) 特点:线程私有(每个计数器独立计算,上下文相互独立). 2. ...
- 深入理解Java虚拟机--阅读笔记二
垃圾收集器与内存分配策略 一.判断对象是否已死 1.垃圾收集器在对堆进行回收前,要先判断对象是否已死.而判断的算法有引用计数算法和可达性分析算法: 2.引用计数算法是给对象添加引用计数器,有地方引用就 ...
- 深入理解JAVA虚拟机阅读笔记4——虚拟机类加载机制
虚拟机把描述类的Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 在Java语言中,类型的加载.连接和初始化过程都是 ...
- 深入理解JAVA虚拟机阅读笔记1——JAVA内存区域
一.Java内存区域 1.程序计数器 线程私有. 当前线程所执行的字节码的行号指示器.由于JAVA是多线程的,因此每个线程都独立的程序计数器. 异常:没有规定任何OutOfMemeryError情况的 ...
- 深入理解java虚拟机阅读笔记(1)运行时数据区域
java虚拟机所管理的内存区域主要分为方法区.堆:虚拟机栈.本地方法栈.程序计数器,如图: 1.程序计数器是当前线程所执行的字节码行号指示器,用以记录当前指令执行的位置.程序计数器是线程私有的,每个线 ...
- 深入理解JAVA虚拟机阅读笔记6——线程安全与锁优化
线程安全:如果一个对象可以安全的被多个线程同时使用,那它就是线程安全的. 一.Java中的线程安全 1.不可变 不可变的对象一定是线程安全的.String.枚举类型.java.lang.Number的 ...
- 深入理解JAVA虚拟机阅读笔记3——垃圾回收器
一.垃圾收集器总览 新生代:Serial. ParNew. Parallel Scavenge 老年代:CMS.Serial Old. Parallel Old 最新的:G1 并行和并发的区别: 并行 ...
- 深入理解JAVA虚拟机阅读笔记2——垃圾回收
线程私有的程序计数器.虚拟机栈和本地方法栈随线程而生,随线程而灭.栈中的栈帧随方法的进入和退出有条不紊的入栈和出栈. 而Java堆和方法区因为需要多大内存.创建多少对象都是不确定的,因此这两个区域是垃 ...
- 深入理解Java虚拟机--阅读笔记三
垃圾收集器 手机算法是内存回收的方法论,垃圾收集器是内存回收的具体实现. 并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态 并发:值用户线程与垃圾收集线程同时执行(但并不一定是并行的) ...
随机推荐
- MVC 5使用ViewBag(对象)显示数据
前面Insus.NET有演示使用ViewData来实现控制器与视图的通讯.如果想了解的话,可以从下面两个链接可以查看:<MVC 5使用ViewData(对象)显示数据>http://www ...
- maven build的常用生命周期
常用的maven build goals: validate - validate the project is correct and all necessary information is av ...
- centos7 升级GCC版本到7.3.0
废话不多说,直接上shell,还是比较简单的.就是编译时间有点长... 都是以小时计的......,我刀片机上面一台虚拟机反正是等了3个小时 #必备组件安装 yum install -y gcc gc ...
- odoo开发笔记 -- 安装Backend debranding去除odoo信息模块后 隐藏开发者模式
Backend debranding 找到如下文件,将相关灰色代码注释掉. <?xml version="1.0" encoding="UTF-8"?&g ...
- 剑指offer十六之合并两个排序的链表
一.题目 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 二.思路 注:链表1和链表2是两个递增排序的链表,合并这两个链表得到升序链表为链表3. 首先分析 ...
- nc命令简介
nc介绍 ncat/nc 既是一个端口扫描工具,也是一款安全工具,还能是一款监测工具,甚至可以做为一个简单的 TCP 代理. 在大多数 Debian 发行版中,nc 是默认可用的,它会在安装系统的过程 ...
- webgl之五彩光源
一.Three.js中有哪些光源? 在Three.js中,光源有一个基类THREE.Light(hex),这个hex接受16进制颜色作为参数而初始化光源的颜色,比如我们要定义一种绿色的光源,可以这样来 ...
- Python -----issubclass和isinstance
issubclass用于判断一个类是否为另一个类的子类,isinstance用于判断一个对象是否某类的一个实例 import math class Point: def __init__(self, ...
- JSPatch动态更新APP
JSPatch,只需在项目中引入极小的引擎,就可以使用JavaScript调用任何Objective-C的原生接口,获得脚本语言的能力:动态更新APP,替换项目原生代码修复bug. 用途 是否有过这样 ...
- 解析BroadcastReceiver之你需要了解的一些东东
前些天把四大组件之一的Service扯了一遍,今天就要开始谈谈它的弟兄BroadcastReceiver了.写到这里我挺纠结的,因为广播接收者确实比较简单,但是各位就不要以为简单的就不内涵,也许我们慢 ...