JVM工作原理

JVM的生命周期##

首先分析一下JVM实例和JVM执行引擎实例的区别
JVM实例:JVM实例对应了一个独立运行的java程序
它是进程级别的
JVM执行引擎实例则对应了属于用户运行程序的线程
它是线程级别的

JVM实例的诞生##

当启动一个Java程序时,一个JVM实例就产生了

JVM实例的运行##

main()作为该程序初始线程的起点,任何其他线程均由该线程启动。
JVM内部有两种线程:守护线程和非守护线程
main()属于非守护线程, 守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程

JVM实例的消亡

当程序中的所有非守护线程都终止时,JVM才退出;
若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出

JVM的体系结构##

Paste_Image.png

JVM的内部体系结构分为三部分:##

(1)类加载器(ClassLoader)子系统
作用:用来装载.class文件
(2)执行引擎
作用:执行字节码,或者执行本地方法
(3)运行时数据区
方法区,堆,PC寄存器,本地方法栈

JVM的类加载器##

JVM将整个类加载过程划分为三个步骤:
(1)装载
装载过程负责找到二进制字节码并加载至JVM中
JVM通过类名、类所在的包名通过ClassLoader来完成类的加载
同样,也采用以上三个元素来标识一个被加载了的类:类名+包名+ClassLoader实例ID。
(2)链接
链接过程负责对二进制字节码的格式进行校验、 初始化装载类中的静态变量以及解析类中调用的接口、类。
在完成了校验后,JVM初始化类中的静态变量,并将其值赋为默认值。
最后一步为对类中的所有属性、方法进行验证, 以确保其需要调用的属性、方法存在,以及具备应的权限(例如public、private域权限等), 会造成NoSuchMethodError、NoSuchFieldError等错误信息。
(3)初始化
初始化过程即为执行类中的静态初始化代码、构造器代码以及静态属性的初始化
在四种情况下初始化过程会被触发执行:

                                            1.调用了new; 
                                            2.反射调用了类中的方法; 
                                            3.子类调用了初始化; 
                                            4.JVM启动过程中指定的初始化类。

JVM执行引擎##

JVM通过执行引擎来完成字节码的执行,在执行过程中JVM采用的是自己的一套指令系统,每个线程在创建后,都会产生一个程序计数器(pc)和栈(Stack),其中程序计数器中存放了下一条将要执行的指令,Stack中存放Stack Frame,表示的为当前正在执行的方法,每个方法的执行都会产生Stack Frame,Stack Frame中存放了传递给方法的参数、方法内的局部变量以及操作数栈,操作数栈用于存放指令运算的中间结果,指令负责从操作数栈中弹出参与运算的操作数,指令执行完毕后再将计算结果压回到操作数栈,当方法执行完毕后则从Stack中弹出,继续其他方法的执行。

JVM运行时数据区##

JVM在运行时将数据划分为了6个区域来存储,而不仅仅是大家熟知的Heap区域,这6个区域图示如下:

Paste_Image.png

第一块: PC寄存器
PC寄存器是用于存储每个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息
第二块:JVM栈
JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量,部分返回结果以及函数的参数值,非基本类型的对象的JVM栈上仅存放一个指向堆上的地址
第三块:堆(Heap)
Heap是大家最为熟悉的区域,它是JVM用来存储对象实例以及数组值的区域,可以认为java中所有通过New创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收
第四块:方法区域(Method Area)
(1)方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,可见方法区域的重要性,同样,方法区域也是全局共享的,在一定的条件下它也会被GC;当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。
(2)在Sun JDK中这块区域对应的为Permanet Generation,又称为持久代,默认为64M,可通过-XX:PermSize以及-XX:MaxPermSize来指定其大小。
第五块:运行时常量池(Runtime Constant Pool)
类似C中的符号表,存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。
第六块:本地方法堆栈(Native Method Stacks)
JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态

JVM的垃圾回收问题##

GC的基本原理:
为将内存中不再被使用的对象进行回收,GC中用于回收内存中不被使用的对象的方法称为收集器
由于GC需要消耗一些资源和时间的,Java在对对象的生命周期特征进行分析后,采用了分代的方式来进行对象的收集,即按照新生代,旧生代的方式来对对象进行收集
(1)对新生代的对象的收集称为Minor GC
(2)对旧生代的对象的收集称为Full GC
(3)程序中主动调用System.gc()强制执行的GC为Full GC
JVM中自动内存回收机制
(1)引用计数收集器
原理:引用计数是标识Heap中对象状态最明显的一种方法
引用计数的方法简单来说就是对每一个对象都提供一个关联的引用计数,以此来标识该对象是否被使用,当这个计数为零时,说明这个对象已经不再被使用了
优点:
引用计数的好处是可以不用暂停应用,当计数变零时,即可将此对象的内存空间回收,但它需要给每个对象附加一个关联引用计数
缺点:
引用计数无法解决循环引用的问题,因此JVM并没有采用引用计数
(2)跟踪收集器
原理:
跟踪收集器的方法为停止应用的工作,然后开始跟踪对象,跟踪时从对象根开始沿着引用跟踪,直到检查完所有的对象
根对象的来源主要有三种:
1.被加载的类的常量池中的对象引用
2.传到本地方法中,没有被本地方法"释放"的对象引用
3.虚拟机运行时数据区从垃圾收集器的堆中分配的部分
存在问题:
跟踪收集器采用的均为扫描的方法,
但JVM将Heap分为了新生代和旧生代, 在进行minor GC时需要扫描是否有旧生代引用了新生代中的对象, 但又不可能每次minor GC都扫描整个旧生代中的对象,
因此JVM采用了一种称为卡片标记(Card Marking)的算法来避免这种现象。
(3)卡片标记算法
卡片标记的算法为将旧生代以某个大小(例如512字节)进行划分,划分出来的每个区域称为卡片, JVM采用卡表维护卡的状态,每张卡片在卡表中占用一个字节的标识(有些JVM实现可能会不同), 当Java代码执行过程中发现旧生代的对象引用或释放了对于新生代对象的引用时, 就相应的修改卡表中卡的状态,每次Minor GC只需扫描卡表中标识为脏状态的卡中的对象即可

Paste_Image.png

JVM中将对象的引用分为四种类型,不同的对象引用类型会造成GC采用不同的方法进行回收:
(1)强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)
(2)软引用:软引用是java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)
(3)弱引用:在GC时一定会被GC回收
(4)虚引用:由于虚引用只是用来得知对象是否被GC

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • JVM内存模型Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: ...
    光剑书架上的书阅读 2,477评论 2 26
  • 原文阅读 前言 这段时间懈怠了,罪过! 最近看到有同事也开始用上了微信公众号写博客了,挺好的~给他们点赞,这博客我...
    码农戏码阅读 5,946评论 2 31
  • 这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的...
    高广超阅读 15,527评论 3 83
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,170评论 11 349
  • 那年,记不得是哪一年,只是印象着春风吹卷着阵阵丁香的味。我只是孩子,也许天真也许青春,总该就是在那样一个最爱幻想的...
    眼白阅读 203评论 0 0