- 博客(27)
- 收藏
- 关注
原创 JVM编译器优化技术
文章目录方法内联逃逸分析方法内联方法内联就是把目标方法的代码原封不动地“复制”到发起调用的方法中,避免发生真实的方法调用。但是在java虚拟机中,只有使用invokespecial指令调用的私有方法、实例构造器、父类方法和使用invokestatic指令调用的静态方法是在编译期进行解析的,还有使用final修饰的方法可以确定唯一的版本。java中大多数方法调用都必须在运行时确定方法接收者的动态选择,他们的方法接受者可能多于一个。为了解决虚方法内联问题,java虚拟机引入了类型继承关系分析(Class
2021-07-20 14:44:00
204
原创 JVM即时编译器
文章目录概述解释器与编译器概述Java程序最初都是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码的运行特别频繁,就会把这些代码认定为“热点代码”(Hot Spot Code),为了提高热点代码的执行效率,在运行时,虚拟机会把这些代码编译成本地代码,并以各种手段尽可能的进行代码优化,运行时完成这个任务的后端编译器被称为即时编译器。解释器与编译器当程序需要快速启动和执行的时候,解释器可以首先发挥作用省去编译的时间,立即运行。当程序启动后,随着时间的推移,编译器逐渐发挥作用
2021-07-13 08:35:12
326
原创 Java基于栈的字节码执行引擎
文章目录编译执行和解释执行基于栈的指令集基于栈的解释执行过程编译执行和解释执行许多Java虚拟机的执行引擎在执行Java代码的时候都有解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种选择。Java语言经常被人定义为“解释执行的语言”,在Java初生的JDK 1.0时代,这种定义还算准确,但当前主流的虚拟机当中都包含了及时编译器后,Class文件中的代码到底会被解释执行还是编译执行,就成了只有虚拟机自己才能知道的事。大部分程序代码转化成物理机目标代码或虚拟机能执行的指令集之前,
2021-07-07 10:21:05
198
原创 Java虚拟机方法调用
文章目录概述解析分派静态分派动态分派单分派和多分派虚拟机动态分派的实现概述方法的调用并不等同于方法中的代码被执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还未涉及方法内部的具体运行过程。Class文件编译的过程不包含传统程序语言的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的地址(也就是之前所说的直接引用)。解析在Java语言中“编译期可知,运行期不可变”的方法,会在加载解析阶段会将Class文件常量池中的符号引用转
2021-07-06 08:10:57
309
原创 Java虚拟机运行时栈结构
目录概述局部变量表操作数栈动态链接方法返回地址附加信息概述Java虚拟机以方法作为最基本的执行单元,栈帧(Stack Frame)则是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的栈(Virtual Machine Stack)的栈元素。栈存储了方法局部变量表、操作数栈、动态链接和方法返回地址等信息,每一个方法从调用开始到执行结束的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。在活动的线程中,只有位于栈顶的方法才是运行的,只有位于栈顶的栈帧才是有效的,其被称为
2021-07-01 09:09:36
158
原创 Java虚拟机类加载机制
目录概述双亲委派模式破坏双亲委派模型概述通过一个类的全限定名来获取描述该类的二进制字节流,实现这个动作的代码被称为“类加载器”(Class Loader)。这个动作可以放到Java虚拟机外部实现,以便让应用程序自己去决定如何去获取所需的类。对于任何一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性。每一个类加载器都有一个独立的类名称空间。双亲委派模式站在Java虚拟机的角度来看,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoade
2021-06-28 14:22:33
50
原创 Java虚拟机类加载机制
文章目录概述类加载的时机类加载过程概述Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化、最终行程可以被虚拟机直接使用的类型,这个过程被称为虚拟机类加载机制。在Java语言里面,类的加载、连接和初始化过程实在程序运行期间完成的,这种策略让Java语言进行提前编译会面临额外的困难,也会让类加载时稍微增加一些性能的开销,但是却为java应用提供了极高的扩展和灵活性,Java天生可以动态扩展的语言特性就是依赖运行期动态加载和动态链接这个特点实现的。类加载的时机一个类
2021-06-24 15:24:33
120
原创 Java虚拟机字节码指令简介
文章目录前言一、字节码和数据类型加载和存储指令运算指令前言Java虚拟机指令是由一个字节长度的、代表着某种特定操作含义的数字(称为操作码)以及跟随其后的零至多个代表此操作的参数(称为操作数)构成。Java虚拟机采用的时面向操作数栈的架构,所以大多数指令不包含操作数,只有一个操作码,指令参数存放在操作数栈中。在不考虑异常的情况下,Java虚拟机的操作模型如下: do{ 自动计算PC寄存器的值加1; 根据PC寄存器指示的位置,从字节码流中取出操作码; if(字节码存在操作数)从字节码流中.
2021-06-18 11:11:02
709
原创 JAVA Class类文件结构
文章目录前言一、魔数与Class文件的版本1.魔数2.文件版本号前言Class文件是一组以8个字节为进出单位的二进制流,各个数据项目严格按照顺序紧凑的排列在文件中,中间没有任何的分隔符。当遇到占用8个字节以上空间数据项时,则会按照高位在前的方式进行分割成若干个8字节进行存储。Java文件格式采用一种类似C语言结构体的伪结构来存储数据,这种伪结构只有两种数据类型:“无符号数”和“表”。无符号数属于基本的结构类型,以u1、u2、u4、u8来分别标识1字节、2字节、4字节和8字节的无符号数,无符号数可以
2021-06-17 10:21:10
331
原创 Java虚拟机内存监控工具-jstack
生成虚拟机当前时刻线程快照(一般称为thread或者javacore文件),线程快照是当前虚拟机内每一条线程正在执行的方法堆栈集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因。命令格式 jstack [option] vmid option:选项作用-F当正常的输出的请求不被响应强制输出线程堆栈-l除堆栈外,显示关于锁的附加信息-m如果调用到本地方法的话,可以显示C/C++的堆栈...
2021-06-04 11:26:51
79
原创 Java虚拟机内存监控工具-jmap
用于生成堆转存快照(一般称为heapdump或dump文件),查询finalize执行队列,java堆信息和方法区的详细信息,如空间使用率,当前用的垃圾收集器等。命令格式: jmap [option] vmid option:选项作用-dump生成Java堆转储快照。格式为 -dump:[live,]format=b,file=,其中live子参数说明是否值dump出活的对象-finalizerinfo显示在F-Queue中等待Finalizer线程执行finali
2021-06-04 11:13:00
160
原创 Java虚拟机内存监控工具-jinfo
实时查看和调整虚拟机各项参数。如果是JDK6及以上版本,使用 java -XX:PrintFlagsFinal查看参数默认值。jinfo -sysprops pid 可以把虚拟机进程的System.getProperotes()的内容打印出来。jinfo -flag [+/-]name pid 或者 jinfo -flag name=value pid在运行期间修改一部分运行期间可写的虚拟机参数值。jinfo -flag name pid 查询参数值虚拟机垃圾收集器参数:参数描述
2021-06-04 10:43:23
89
原创 Java虚拟机内存监控工具-jstat
jstat用于监视虚拟机各种运行状态的命令行工具,可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、及时编译等运行时数据。 jstat命令格式: jstat [option vmid [interval[s|ms] [count]] ] vmid: 对于本地虚拟机VMID和LVMID是一致的,如果是远程虚拟机进程,那么VMID的格式: [protocol:][//]lvmid[@hostname[:port]/servername] interval和count:
2021-06-04 10:21:21
198
原创 Java虚拟机内存监控工具-jps
jps列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)的名称以及这些进程的本地虚拟机唯一ID(LVMID),LVMID与操作系统的进程ID是一致的。可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态。命令格式: jps [options] [hostid] hostid: 为RMI注册表中注册的主机名。&
2021-06-04 09:48:51
121
原创 java虚拟机垃圾收集器参数
参数描述UseSerialGC虚拟机在Client模式下的默认值,打开此处开关之后,使用Serial+Serial Old收集器组合进行内存回收UseParNewGC打开此开关之后,使用ParNew + Serial Old的收集器组合进行内存回收,在JDK9之后不支持UseConcMarkSweepGC打开开关之后,使用ParNew + CMS + Serial Old的收集器组合进行内存回收。Serial Old收集器将作为CMS收集器出现“Conncurrent ...
2021-06-03 09:18:41
123
原创 JVM垃圾收集器
Serial收集器使用单线程工作的收集器,但它的“单线程”的意义并不仅仅是说明它只会使用一个处理器或者一条线程去完成垃圾收集工作、更重要的是强调它在垃圾收集时,必须暂停其它所有工作线程,直到收集结束。它是HotSpot虚拟机运行运行在客户端模式下的默认收集器,有着由于其它收集器的地方,那就是简单而高效(与其它单线程的收集器相比),对于内存资源受限的环境,它是所有收集器里额外内存消耗最小的,在单核处理器或处理器核心数较少的环境来说,Serial收集器由于没有线程开销,专心做垃圾收集自然可以获得最高的单线程收
2021-05-28 10:47:38
53
原创 JVM垃圾收集算法-HotSpot的算法实现细节
根节点枚举 固定可作为GC Roots的节点主要在全局性的引用(例如常量和类静态属性)与执行上下文(例如栈帧中的本地变量)中,尽管目标明确,但是查找过程要做到高效并非一件容易的事情,特别是java项目越来越庞大。 目前主流Java虚拟机使用的都是准确式垃圾收集,所以用户停下来之后并不需要一个不漏的检查完所有执行上下文和全局引用位置。在HotSpot的解决方案里使用OopMap的数据结构来达到这个目的,一旦类加载完
2021-05-27 14:20:22
105
原创 JVM之垃圾收集算法
分代收集理论分代收集理论建立在下面两个假说之上:弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕死。强分带假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。根据这两条假说设计的垃圾收集原则:收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄分配到不同的区域中存储。设计者一般至少把Java堆划分为新生代(Young Generation)和老年代(Old Generat
2021-05-26 11:34:49
56
原创 JVM怎么判断对象可回收
引用计数法在对象中添加一个引用计数器每当有一个地方引用它的时候,计数器的值就加一;当引用失效的时,计数器的值就减一;任何时刻计数器为零的对象就是不可能再被使用。但是这种算法不能解决循环引用的问题。可达性分析算法通过一系列称为“GC Roots”的根对象作为起始节点集,根据这些节点开始,根据引用开始向下搜索,搜索过程中所走过得路径称为“引用链”(Reference Chain),如果某个对象到“GC Roots”没有任何引用链,则证明这个对象不可能再被使用。可以作为GC Roots的对象:在虚拟机
2021-05-25 09:28:49
79
原创 HotSpot虚拟机对象探秘
对象的创建当JVM遇到一个new指令时,首先会去检查这个指令参数是否能在常量池中定位到一个类的符号引用,并检查这个类的符号引用代表的类是否已被加载、解析和初始化过,如果没有则必须先执行加载过程。类加载检查通过之后,接下来虚拟机将为新生的对象分配内存,对象内存的大小在类加载完成之后便可完全确定。内存的分配方式包含指针碰撞(java堆内存是规整的)或空闲列表(java堆内存是不规整的)。内存分配完之后,虚拟机必须要将分配到的内存空间(不包括对象头)都初始化为零。接下来对对象进行必要的设置,例如对象属于
2021-05-21 09:45:42
80
原创 JVM-运行时数据区域
程序计数器JVM字节码解释器工作的时候就是通过改变程序计数器的值来选取下一条需要执行的字节码指令。每一个线程都有一个独立的程序计数器,各个线程之间互不影响,独立存储,这类内存是私有的。如果线程正在执行一个JAVA方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行本地(native)方法,这个计数器的值为空(Undefined)。Java虚拟机栈每个方法再执行的时候,Java虚拟机都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法的
2021-05-20 09:30:03
58
原创 java并发编程的艺术-ReentrantLock公平锁原理分析
lock方法分析 final void lock() { acquire(1); }该lock方法会调用AbstractQueuedSynchronizer的acquire方法 /** * Acquires in exclusive mode, ignoring interrupts. Implemented * by invoking at least once {@link #tryAcquire}, * returning on succ
2021-04-27 16:39:40
99
原创 java并发编程的艺术学习笔记-java并发编程的基础
什么是线程 现代的操作系统运行一个程序时,会为其创建一个进程。在一个进程里可以创建多个线程,线程是操作系统调度的最小单元,也叫轻量级进程,这些线程拥有各自的计数器、堆栈和局部变量,并且能够共享内存变量。 现在操作系统基本采用时分的形式调度运行的线程,操作系统会分出一个个时间片,线程会分配到若干个时间片,当线程的时间片用完了就会发生线程的调度,并等待下次分配。线程优先级越高线程分配的时间片数量就越多。线程的状态状态名称说明NEW
2021-04-25 16:27:03
71
原创 java并发编程的艺术学习笔记-happens-before
JMM的设计JMM的设计一方面要为程序员提供足够强的内存可见性;另一方面对编译器和处理器的限制要尽可能的放松。对于改变程序结果的重排序,JMM要求编辑器和处理器必须禁止这种重排序。对于不改变程序执行结果的重排序,JMM对编译器和处理器不做要求。只要不改变程序的执行结果(指的是单线程和正确同步的多线程),编译器和处理器怎么优化都可以。happens-before的定义如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而第一个操作的执行顺序排在第二个操
2021-04-22 14:53:49
198
1
原创 java并发编程的艺术学习笔记-final的内存语义
final的重排序规则在构造函数内对一个final域的写入,与随后把这个构造对象的引用赋值给一个引用变量,这两个操作不能重排序。初次读一个包含final的对象引用,与随后初次读这个final域,这两个操作不能重排序。写final重排序规则写重排序规则进制把final域的写重排序到函数之外,两个方面的实现:JMM进制编译器把final域的写重排序到函数之外。编译器会在final写域之后,构造函数return之前,插入一个StoreStore屏障。这个屏障禁止处理器把final域重排序到构造函
2021-04-20 10:30:47
110
原创 java并发编程的艺术学习笔记-volatile和锁的内存语义
volatile写-读的内存语义volatile写内存定义:当写一个volatile内存变量的时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。也就是说当写一个volatile变量的时候,之前共享变量的操作结果要刷新到主内存,之前的操作不能重排序到该操作之后。volatile读内存定义:当读一个volatile内存变量的时,JMM会把线程对应的本地内存置为无效。线程接下来从内存中读取共享变量。也就是说当读一个volatile变量时,会从内存中加载到本地内存中,之后对共享变量的操作的值要重新获
2021-04-16 10:39:38
73
原创 java并发编程的艺术学习笔记-java内存模型
java内存模型抽象java的所有实例域、静态域和数组元素都存储在堆内存中,堆内存在线程之间共享局部变量、方法定义参数和异常处理参数不会再线程之间共享,不会存在内存可见性问题,也不受内存模型的影响。线程之间的共享变量存储在主内存中,每个线程都有一个本地内存,本地内存存储了该线程以读/写共享变量的副本指令重排序包含编译器优化重排序、指令集并行重排序和内存系统重排序java内存模型通过插入特定类型的内存屏障指令,来禁止特定类型处理器的重排序每个处理器都有写缓冲区,仅对它所在的处理器可见,处理器对
2021-04-15 07:54:11
89
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人