《刘瑜写给女儿的信:愿你慢慢长大 》
小布谷,愿你慢慢长大。
愿你有好运气,如果没有,愿你在不幸中学会慈悲。
愿你被很多人爱,如果没有,愿你在寂寞中学会宽容。
愿你一生一世每天都可以睡到自然醒。
I am BlankCat ,welcome to my blog;
技术要点
|
|
BlankCat
《刘瑜写给女儿的信:愿你慢慢长大 》
小布谷,愿你慢慢长大。
愿你有好运气,如果没有,愿你在不幸中学会慈悲。
愿你被很多人爱,如果没有,愿你在寂寞中学会宽容。
愿你一生一世每天都可以睡到自然醒。
I am BlankCat ,welcome to my blog;
|
|
I am BlankCat,welcome to my blog;
|
|
Java程序最初是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为『热点代码』。为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器。
HotSpot虚拟机是采用解释器与编译器并存的架构。解释器和编译器各有优势:当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器初见发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。
在运行过程中被即时编译器编译的『热点代码』有两类:
执行引擎是Java虚拟机最核心的组成部分之一,本章将主要从概念模型的角度来讲解虚拟机的方法调用和字节码执行。
栈帧(Stack Frame)是用于支持虚拟机进行方法代用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机里面从入栈到出栈的过程。对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧,与这个栈帧相关联的方法称为当前方法,执行引擎运行的所有字节码指令都只针对当前栈帧进行操作,在概念模型上,典型的栈帧结构图如下:
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
类被夹在到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载7个阶段。其中验证、准备、解析3个部分统称为连接,这个阶段的发生顺序如下图所示:
本章说一下Java编译后的class文件结构。
我这里用sublime打开一个class文件,看到前面4个字节是十六进制0xCAFEBABE,这个是Class文件的魔数.
很多文件存储标准中都使用魔数进行身份识别,因为扩展名可以更改,魔数就是确定这个文件是否为一个能被虚拟机接受的Class文件。
然后看0000 0034,转换成十进制是52,这个表示Java编译的版本号,相信大家在工作中也遇见过Unsupported major.minor version 52.0
之类的错误,指的就是这个版本号,52对应的是JDK8。
给一个系统定位问题的时候,知识、经验是关键基础,数据是依据,工具是运用知识处理数据的手段。这里说的数据包括:运行日志、异常堆栈、GC日志、线程快照(threaddump/javacore文件)、堆转储快照(heapdump/hprof文件)等。经常使用适当的虚拟机监控和分析的工具可以加快我们分析数据、定位问题的速度。
JDK的安装目录bin下提供了很多工具,这些工具其实是jdk/lib/tools.jar的包装而已。
jps(JVM Process Status Tool):可以列出正在运行的虚拟机进城,并显示虚拟机执行主类以及这些进城的本地虚拟机唯一ID(Local Virtual Machine IIdentifier, LVMID),这个LVMID跟系统里的PID是一致的。
之前讲了垃圾回收器体系以及运作原理,现在来看看对象内存分配那点事儿。对象的内存分配,往大方向讲就是在堆上分配,对象主要分配在新生代的Eden区上,也可能直接分配在老年代中,并不固定,取决于使用的哪一种垃圾收集器以及虚拟机参数设置。
大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够的空间进行分配时,虚拟机会发一起一次Minor GC。
程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭,方法或者线程结束的时候内存自然就跟着回收了,所以不需要考虑过多回收的问题。而Java堆和方法区就不一样了,这部分内存的分配和回收都是动态的。
因为堆就是放对象的地方,要回收内存,首先要知道哪些对象是不可能再被任何途径使用的
这个算法的实现是:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器+1,当引用失效时,计数器-1。Object-C就是使用的这种方式,Java没有选用引用计数算法来管理内存,因为它很难解决对象之间相互循环引用的问题。例子如下
在Java虚拟机规范的描述中,除了程序计数器,其他几个运行时区域都有发生OutOfMemoryError异常的可能。本文有两个目的:
这个图展示了如何在Idea中设置VM参数。