JVM虚拟机基本概念
一、JVM运行时数据区域
1.1、程序计数器
一块较小的内存空间,当前线程所执行的字节码指示器。每个线程有一个独立的程序计数器
1.2、Java虚拟机栈
线程私有,生命周期与线程相同
每个方法在执行时会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息
64位的long和double类型的数据会占用两个局部变量空间,其余数据类型占用1个
局部变量表存放了编译期间可知的各种基本数据类型,对象的引用
异常:1)线程请求的深度大于虚拟机所允许的深度,抛出StackOverflowError
2)如果虚拟机可以动态扩展,扩展时无法申请到足够的内存,抛出OutOfMemoryError
1.3、本地方法栈
与虚拟机栈作用相似,区别就是虚拟机栈执行java方法(字节码服务),方法栈执行的时Native方法服务,也会抛出StackOverflowError和OutOfMemoryError
1.4、java堆
JVM管理最大的一块内存,所有线程共享的一块内存区域,存放实例对象及数组
垃圾收集齐管理的主要区域
,扩展通过-Xmx -Xms控制
1.5、方法区
加载的类信息,常量,静态变量,各线程共享区域
1.6、运行时常量池
方法区的一部分
1.7、直接内存
二、对象的创建【new-->加载类-->分配空间-->设置对象-->init】
1)收到new指令----根据参数检测常量池中定位到类的引用------检查是否被加载,解析,初始化------没有就优先执行类加载
2)类加载完毕----分配内存【1.指针碰撞[空内存与使用内存规则,垃圾收集器需要带压缩整理功能(Serial,ParNew)]2.空闲列表[不规则(CMS)]】
3)内存分配完---内存空间都设置为0,使用TLAB可将此步骤提前到TLAB分配时进行
4)设置对象
5)new 完成之后执行init方法,这样一个真正可用的对象就算生产出来了
6)修改指针的线程安全性
对分配内存的动作进行同步处理
每个线程在java堆中预先分配一小块内存,本地线程分配缓存(TLAB),哪个线程需要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完重新分配时才加同步锁定
,通过参数 -XX:+/-UseTLAB参数设定
三、对象的布局
3.1.分为3块区域 对象头(Header) 实例数据(Instance Data) 对齐填充(Padding)
3.2.Header:对象自身运行时数据,哈希码,GC分代年龄,锁状态标识等
3.3.实例数据部分:对象真正存储的有效信息
3.4.对齐填充:不是必然存在的,占位符的作用,对象的大小必须是8字节的整数倍
四、对象的访问定位
4.1.通过栈上的reference数据来操作堆上的具体对象,访问方式:句柄访问和直接指针两种
4.2.句柄访问:java堆中将会划分出一块内存来做句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据与类型数据各自的具体地址信息
4.3.直接指针:reference中存储的直接就是对象地址
4.4.句柄最大好处就是reference中存储的时稳定的句柄地址,在对象移动时只会改变句柄中的实力数据指针,reference本身不需要修改
4.5.直接指针:速度快,节省了一次指针定位的时间开销
4.6.引用:如果reference类型的数据中存储的数值是另外一块内存的起始位置就称这块内存代表这一个引用
4.7.判断对象是否存活
引用计数器算法 可达性分析算法
4.8.可做Roots对象
虚拟机栈中引用的对象 方法区中静态属性引用 方法区中常量引用的对象 本地方法栈中引用的对象
4.9.引用分类
强引用 弱引用 虚引用 软引用
4.9.1.强引用:程序代码中普遍存在的,Object obj = new Object();只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象
4.9.2.软引用:一些还有用但并非必须的对象,在系统发生内存溢出异常之前,会把这些对象列进回收范围之内进行二次回收,回收之后还没有足够的内存才会抛出
内存溢出,JDK1.2提供了SoftReference实现软引用
4.9.3.弱引用:非必须对象,强度比软引用更弱一些,只能生存到下一次垃圾手机发生之前,WeakReference实现弱引用
4.9.4.虚引用:幽灵引用或幻影引用,最弱的引用关系,PhanttomReference
4.9.5.可达性分析算法计算不可达也不会真正认为对象死亡,需要再经果两次标记 1)标记是否需要执行finalize()方法 2)有必要执行放入F-Queue队列,GC会对里
面的对象进行二次标记
五、垃圾收集算法
5.1.标记-清除算法
两个阶段:1)标记所有需要回收的对象 2)标记完成后统一回收所有被标记的对象
缺点:效率不高,两个阶段都不高 会产生大量不连续的内存碎片,分配较大对象的时候会由于找不到连续的较大内存不得不触发另一次垃圾回收动作
5.2.复制算法
将内存按容量大小分配为相等的两块,每次只使用其中的一块,当一块用完之后将还存活的对象复制到另外一块上去,然后再把使用过的内存空间清理掉,简单高效
,代价就是将内存缩小为原来的一半
5.3.分代收集算法
Java堆分成新生代和老生代,新生代采用复制算法,老生代采用标记-清除的算法
六、垃圾收集器
Serial收集器
最基本.发展历史最悠久的收集器
单线程收集齐
工作时必须暂停其他所有的工作线程,直到收集结束
parNew收集齐
Serial收集器的多线程版本
出了Serial收集齐外,唯一可以与CMS一起使用的收集器
-XX:+UseConcMarkSweepGC默认使用
-XX:+UseParNewGC强制指定
默认开启的线程和CPU数量相同,可使用-XX:ParallelGCThreads参数限制垃圾收集器线程数量
parallel scavenge收集器
新生代收集器,并行多线程收集器
关注的是吞吐量 运行用户代码时间/(运行用户代码时间+垃圾收集器时间)
-XX:MaxGCPauseMillis最大垃圾收集停顿时间 -XX:GCTimeRatio 吞吐量大小
Serial Old收集器
老年代收集器,单线程,使用标记-整理算法
parallel old
老年代收集器,多线程
cms收集器
以获取最短回收停顿时间为目标的收集器
标记-清除算法
分为4步骤 初始标记 并发标记 重新标记 并发清除
JDK1.6 默认触发阈值为92% 可使用-XX:CMSInitiatingOccupancyFraction
G1收集器
并行与并发
分代收集
空间整合
可预测的停顿
七、内存分配与回收策略
7.1.内存管理可以归结为自动化解决两个问题:给对象分配内存以及回收分配给对象的内存
7.2.对象优先再Eden分配
大多数情况下,对象在新生代Eden区中分配,当Eden不足分配时,虚拟机将发起一次Minor GC
-XX:+PrintGCDetails打印回收日志
7.3.大对象直接进入老年代
需要连续内存空间的java对象,长字符串以及数组
-XX:PretenureSizeThreshold设置值的对象直接在老年代分配
7.4.长期存活的对象将进入老年代
对象年龄,在新生代经果一次Minor GC后仍然存活,并能被Survivor容纳的话就被移到Survivor空间中,并且对象年龄为1,在Survivor区中每经过一次Monir GC
年龄+1,默认为15岁晋升到老年代
通过-XX:MaxTenuringThreshold设置阈值
7.5.动态对象年龄判断
虚拟机并不是永远要求对象的年龄必须到达了阈值才会进入老年代,如果Survivor空间中相同年龄所有对象大于Survivor空间的一半,年龄大于或等于改年龄的对象
直接进入老年代
八、虚拟机性能监控与故障处理工具
8.1.jps 显示指定系统内的HotSpot虚拟机进程
jstat 用于收集HotSpot虚拟机各方面的运行数据
jinfo 显示虚拟机配置信息
jmap 生成虚拟机的内存转储快照
jhat 用于分析heapdump文件,它会建立一个HTTP/HTML服务器,让用户可以在浏览器上分析结果
jstack 显示虚拟机的线程快照
九、内存间交互操作
9.1.lock:锁定,作用于主内存的变量,把变量标识为一条线程独占的状态
unlock:解锁,作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放之后的变量才可以被其它线程锁定
read:读取,作用于主内存的变量,它把一个变量从主内存从传输到线程的工作内存中,以便随后的load动作使用
load:载入,作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
use:使用,作用于工作内存,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作
assign:赋值,作用于工作内存,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作
store:存储,作用于工作内存,它把工作内存中的一个变量的值传送到主内存中,以便随后的write操作
write:写入,作用于主内存,它把store操作从工作内存中得到的变量值放入到主内存的变量中
9.2.变量内存交互限制
1)不允许read和load,store和write单独出现
2)不允许一个线程丢弃它最近的assign操作,即变量在工作内存改变了之后必须写回主内存
3)不允许一个线程没有assign操作,就把变量同步回主内存
4)变量的诞生必须在主内存,不允许在工作内存使用一个未被初始化(load和assign)的变量,在use.store之前必须执行load和assign操作
5)一个变量在同一时刻只允许一条线程对其进行lock操作操作,但lock操作可以被同一条线程多次执行
6)如果对一个变量执行lock之后,那将会清空工作内存此变量的只,在执行引擎使用这个变量前,需要重新执行load和assign操作
7)如果一个变量事先没有执行后lock操作,不允许执行unlock操作
8)对一个变量执行unlock之前,必须先把此变量同步回主内存中
9.3.volatile 最轻量级的同步机制
保证此变量的可见性
volatile变量一条线程修改变量值,新值对于其它线程来说是可以立即得知的
普通变量需要通过主内存的来完成,线程A修改了变量age,需要先回写回主内存,线程B等线程A回写完成之后再从主内存进行读取操作
禁止指令重排序优化
9.4.先行发生原则
判断数据是否存在竞争,线程是否安全的主要依据
1)如果线程A先行发生于操作B,操作A产生的影响能被操作B观察到
2)程序次序规则:在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于写在后面的操作
3)管程锁定规则:一个unlock操作先行发生于后面对同锁的lock操作【时间先后】
4)volatile变量规则:对一个volatile变量的写操错先行发生于后面这个变量的读操作【时间先后】
5)线程启动规则:Thread对象的start()方法先行发生于此线程的每个动作
6)线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测
7)线程中断规则:对线程interrup()方法的调用先行发生于被中断的代码检测到中断事件的发生
8)对象终结规则:一个对象的初始化完成先行发生于finalize()方法的开始
9)传递性:A>B B>C 则 A>C
十.线程的实现
使用内核线程实现,使用用户线程实现,用户线程加轻量级进程
JVM虚拟机基本概念的更多相关文章
- 【JVM虚拟机】(9)-- JVM是如何处理异常的
[JVM虚拟机](9)-- JVM是如何处理异常的 上篇博客我们简单说过异常信息是存放在属性表集合中的Code属性表里,那么这篇博客就单独讲Code属性表中的exception_table. 在讲之前 ...
- 【JVM虚拟机】(8)--深入理解Class中--方法、属性表集合
#[JVM虚拟机](8)--深入理解Class中--方法.属性表集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机] ...
- 【JVM虚拟机】(7)---深入理解Class中-属性集合
#[JVM虚拟机](7)---深入理解Class中-属性集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机](6)- ...
- 【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引
JVM(6)访问标志,类索引 上一篇博客讲[JVM虚拟机](5)---深入理解JVM-Class中常量池 我们知道一个class文件正常可以分为7个部分: 魔数与class文件版本 常量池 访问标志 ...
- 【JVM虚拟机】(5)---深入理解JVM-Class中常量池
深入理解Class---常量池 一.概念 1.jvm生命周期 启动:当启动一个java程序时,一个jvm实例就诞生了,任何一个拥有main方法的class都可以作为jvm实例运行的起点. 运行:mai ...
- 学习JVM虚拟机原理总结
0x00:JAVA虚拟机的前世今生 1991年,在Sun公司工作期间,詹姆斯·高斯林和一群技术人员创建了一个名为Oak的项目,旨在开发运行于虚拟机的编程语言,允许程序多平台上运行.后来,这项工作就演变 ...
- 深入理解JVM虚拟机11:Java内存异常原理与实践
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- 深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- JVM虚拟机运行机制
JVM虚拟机运行机制 什么是JVM?虚拟机是物理机器的软件实现.Java是用在VM上运行的WORA(Write Once Run Anywhere)概念而开发的.编译器将Java文件编译为Java . ...
随机推荐
- 对SVN的落地与实践总结
现今最为流行的Git是管理很几套很成熟的分支管理策略.而SVN确实也有,但结合现公司的实际场景还是做了些调整和变动. 一.分支命名规则 所有分支命名采用小写字母 + 数字 + 特殊符号 组成 项目分支 ...
- 【Android Studio安装部署系列】十七、Android studio引用第三方库、jar、so、arr文件
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 在Android开发过程,经常需要用到第三方库以及jar.so.arr文件,那么如何引用到项目中呢?下面简单介绍下. 引用第三方库 ...
- uni-app—从安装到卸载
uni-app实现了一套代码,同时运行到多个平台.支持iOS模拟器.Android模拟器.H5.微信开发者工具.支付宝小程序Studio.百度开发者工具.字节跳动开发者工具 工具安装 开发uni-ap ...
- iOS----------Mac维修预约-如何找到电脑维修单
先打开苹果官网,找到技术支持 2.选择维修选项 3.查看维修状态 4.显示维修时间订单
- SQL Server关于predicate、density、selectivity、cardinality名词浅析
在SQL Server中,我们要看懂执行计划和统计信息,我们可能需要深刻理解一些关键词,例如密度(Density).选择性(Selectivity).谓词(predicate).基数(Cardin ...
- Ginger的第一篇博客
怀着无感的心情,没有技术的身体,写下第一篇博客作为标记. 目前应该会搞清楚数据结构上相关的操作.算法,然后用c语言实现后记录在博客. 我是有目标的咸鱼! 2019/4/19
- #ifndef, #define, #endif 作用
#ifndef, #define, #endif 作用 https://www.cnblogs.com/challenger-vip/p/3386819.html
- Leetcode 136.只出现一次的数字 By Python
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1: 输入: [ ...
- javascript 字符串转换数字的方法大总结
方法主要有三种 转换函数.强制类型转换.利用js变量弱类型转换. 1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把值转换成浮点数.只有 ...
- SUSE12SP3-Mycat(1)安装
目录 前言 环境 安装说明 安装 1.mycat 2.mycat-eye 前言 介绍自己看. mycat官网:http://www.mycat.io/ 环境 系统: SUSE12SP3 软件 版本 说 ...