简析JVM

本文为阅读《深入理解Java虚拟机》一书的阅读总结,仅围绕JVM如何运行字节码文件(*.class)探究Java虚拟机的运行机制,在本书的基础上对JVM做了更易理解也更为基础的介绍。
我们编写的Java代码文件,如:

public class HelloWorld {
    public static void main(String[] args){
        System.out.pringln("Hello Java!");
    }
}

要以计算机能够理解的方式运行,必须以计算机能够理解的方式沟通,JVM正是这个沟通的媒介,正式因为JVM的存在,Java技术体系才具备了跨平台的优势。
对于JVM来说,它能识别的只是字节码文件,字节码文件具有严格的格式规范,本书的第六章也对此予以了分析,受制于篇幅,本文不予以介绍,详细规范可以参照JVM规范。这也是与平台无关的奥秘所在,本书的JVM并不关心字节码文件编译自何种编程语言,只要编程语言生成的字节码文件满足字节码文件的格式要求,因此Java编程语言只是生成字节码文件的一种途径。
javac命令可以将.java文件编译成.class文件,一个java代码文件或者一个字节码文件相当于一个类或接口(以下统一以类来叙述)的身份描述说明,二者的唯一不同点在于,java 文件是一种程序员可以方便阅读的格式,字节码文件则是JVM方便“阅读”的格式。

类的加载

JVM如何去拿到字节码文件呢?这正是JVM虚拟机的类加载机制,JVM并不关心字节码来源于网络还是本机的磁盘,它认识的只是一串二进制流。
虚拟机把描述类的数据从二进制流加载到内存,在最终形成能被JVM直接使用的类之前,它需要完成以下几件事:

加载

加载过程就是通过类的全限定名获取定义此类的二进制字节流,将字节流所代表的静态存储结构转化为运行时的数据结构,再在内存生成一个代表这个类的的java.lang.Class对象,作为这个类各种数据的访问入口。
实现类加载的代码模块叫做类加载器,每一个类加载器都拥有一个独立的类名称空间,因此,比较两个类是否相等,只有这两个类由同一个类加载器加载才有意义。

校验

之前说过,字节码文有严格的格式要求,有了字节码文件,检查该文件包含的的字节流是否符合当前虚拟机格式的要求,是否存在威胁虚拟机安全的恶意代码,这就是这个阶段要完成的事情。又分为文件格式验证、元数据验证、字节码验证、符号引用验证等多个阶段,整体是一个从形式到内容,从整体到部分的验证过程。

准备

为类变量,即static变量分配存储空间并初始化。

解析

将字节码文件中的符号引用替换为直接引用,符号引用即描述引用目标位置的字面量;直接引用即引用目标实际的内存位置,可以是一个指针,也可以是一个偏移量。

初始化

与前四个步骤不同,类是否初始化有几个触发的必备条件:

  1. new 一个类的实例、读取或设置一个类的静态字段
  2. 反射调用,如果没初始化,则要先初始化
  3. 子类被初始化
  4. 执行主类(包含main方法的类)在虚拟机启动时初始化
    在满足这几个条件中的任意一个后,类加载会进入初始化阶段,执行类的<clinit>()方法。这个方法由编译器自动收集类的所有类变量的赋值动作合并产生。

类信息存放

在类加载的过程中,各种数据如何存放,涉及到JVM的内存模型。
在C、C++中,内存可以看作一个一个的小格子,需要多少的小格子,格子不需要了还都要程序员手动去管理。在Java中,内存的分配由虚拟机的内存管理模块管理,不需要手动去分配和回收。
虚拟机对内存分区是为了简化内存分配和回收这两个过程。
运行时数据区域由以下几个部分构成:
线程共享的区域:

方法区

类被加载后,类信息、常量、静态变量等数据存放到这个区域,反射机制所获取的类的信息就存放在这个区域。对此区域的内存回收比较少见,主要设计到常量池的回收和类型的卸载,回收的效率通常比较低。
运行时常量池是方法区的一部分,主要用来存放编译期生成的各种字面量和符号引用。

堆是虚拟机所管理内存中最大的一块,也是垃圾收集的主要场所,几乎所有的对象实例都在堆上分配内存。

线程私有的内存区域:

程序计数器

虚拟机通过线程轮流切换并分配处理器执行时间来实现多线程操作,在线程不断切换的过程中,每个线程要记住线程恢复后的执行位置即下一条需要执行的指令,因此这个内存区域是线程私有的。

虚拟机栈

虚拟机栈保存的是Java方法的内存模型,和Java方法相关的信息以一个栈帧的形式保存,每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。为线程私有,与线程的生命周期相同。

本地方法栈

本地方法栈与虚拟机栈作用相似,区别在于虚拟机栈为字节码服务,而本地方法栈为虚拟机使用到的Navtive方法服务。

内存回收

在类的加载过程中,虚拟机给它们分配了大量的内存,如果不进行内存回收,注定导致内存溢出。
由于线程私有的内存区域(程序计数器、虚拟机栈、本地方法栈)生命周期和线程相同,它们的内存分配和回收都有确定性。因此垃圾回收主要考虑的是对堆和方法区的回收,这两个区域内存的分配和回收都是动态的。
如何去判断堆中的对象是否该被回收是垃圾回收的核心。

  • 引用计数算法
    有引用,计数器值加1,引用失效,计数器值减1
    存在对象之间循环引用的问题,导致内存无法被回收。
  • 可达性分析算法

垃圾回收算法

  1. 标记-清除算法
    标记所有需要回收的对象,然后统一回收。
    缺点: 标记和清除两个过程效率都不高,产生大量不连续的内存碎片
  2. 复制算法(新生代)
    将内存分为两块,每次只使用其中的一块,当一块的内存使用完了,将还存活的对象复制到另一块上去,为主流商业虚拟机采用回收新生代。
    缺点:可利用空间减小
  3. 标记-整理算法(老年代)
    老年代因为对象存活率较高,使用复制算法效率较低,据此,有人提标记-整理算法,标记过程与标记-清除算法相似,只是后续将存活的对象向一端移动,然后直接清理掉边界以外的内存。

垃圾回收器

目前商用的虚拟机将内存分为新生代和老年代,以HotSpot虚拟机(JDK1.7)为例,根据各个年代的特点和是否多线程的不同,借助七个不同的垃圾收集器来合理的回收内存。

  • Serial收集器
    单线程收集器,在垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束,Client模式下(C1编译,即将字节码简易编译为机器码)默认新生代收集器
  • ParNew收集器
    Serial收集器的多线程版本,虚拟机Server模式(C2编译,在字节码向机器码编译的过程中启用较多的优化)新生代默认收集器
  • Parallel Scavenge 收集器
    与CMS等收集器追求缩短垃圾收集时用户线程的停顿时间不同,Parallel Scavenge收集器的目标是达到一个可控制的吞吐量,即减少垃圾收集的总时间。因此该收集器也被称为“吞吐量优先”收集器。
  • Serial Old收集器
    Serial的老年代版本,单线程收集器,使用标记-整理算法
  • Parallel Old收集器
    配合Parall Scavenge使用,在此收集器之前,Parallel Scavenge 收集器只能搭配Serial Old使用,无法与CMS收集器配合,此收集齐出现后,“吞吐量优先”有了名符其实的组合。
  • CMS 收集器
    以获取最短回收停顿时间为目标的收集器。基于“标记-清除”算法实现,有并发收集、低停顿的优势。
    缺点:
  1. 对CPU资源非常敏感
  2. 无法处理浮动垃圾
  3. 产生大量空间碎片
  • G1收集器
    面向服务端应用,在未来作为CMS收集器的替代者
    特点:
  1. 能够独立管理整个堆
  2. 从整体上来看基于标记-清理算法,局部上来看基于复制算法,不会产生内存空间碎片

分配策略

  1. 对象优先在新生代Eden分配,在Eden没有足够的空间进行分配时,虚拟机将发起一次Minor GC
  2. 大对象直接进入老年代,
  3. 长期存活的对象将进入老年代,在Eden中出生并经过第一次Minor GC 后仍然存活,并且能被Survivor容纳,将被移动到Survivor空间中,每熬过一次Minor GC ,对象的年龄增加1,HotSpot虚拟机默认达到15岁,将会晋升到老年代中。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容