每个java开发同学不管是日常工作中还是面试里,都会遇到JDK、JVM和GC的问题。本文会从以下10个问题为切入点,带着大家了解一下JVM的方方面面。
JVM、JRE和JDK的区别和联系
JVM是什么?以及它的主要作用
JVM的核心功能有哪些
类加载机制和过程
运行时数据区的逻辑结构
JVM的内存模型
如何确定对象是垃圾
垃圾收集的算法有哪些
各种问世的垃圾收集器
JVM调优的参数配置
用一句话评价JVM的主要作用就是:JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
“运行时数据区”是JVM在执行Java程序的过程中出于内存管理方面的目的,在设计上把内存分为若干个不同的区域。这些区域有着各自的用途,有的区域生命周期跟虚拟机一样,随着虚拟机进程的启动而存在,伴随着虚拟机的进程结束而消亡。而有些区域则依赖用户线程的启动和结束而建立和销毁。具体如下图:
1、方法区(Method Area):
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
方法区是各个线程共享的内存区域,在虚拟机启动时创建,因为同一个class类信息只需要加载一份就够了;
java虚拟机规范中把方法区描述为堆内存的一个逻辑部分,但它有另外一个别名叫“非堆”,用于与java堆区分开来。在JDK8之前方法区叫做Perm space,在JDK8及以后叫做Metaspace(即元数据区)。
2、堆(Heap):Java堆是被所有线程共享,虚拟机启动时创建,此内存区域唯一的目的就是存放对象实例,在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展和逃逸分析技术逐渐成熟,栈上分配,标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也就变得不那么绝对了。
3、虚拟机栈(Java Virtual Machine Stacks):虚拟机栈是线程私有的或者说是独有的,随着线程的创建而创建。一个线程的运行状态(正在调用哪个方法),就是由这个线程对应的虚拟机栈来保存的。
每一个被线程执行的方法,为虚拟机栈中的一个栈帧,调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出。如下图解:
4、程序计数器(The Pc Register):我们都知道一个JVM进程中有多个线程在执行,而线程中的内容是否能够拥有执行权,是根据CPU调度来的。假如线程A正在执行到某个地方,突然失去了CPU的执行权,切换到线程B了,然后当线程A再获得CPU执行权的时候,怎么能继续执行呢?这就是需要在线程中维护一个变量,记录线程执行到的位置,这就是程序计数器。
5、本地方法栈(Native Method Stacks):本地方法栈与虚拟机栈所发挥的作用非常相似,他们之间的区别不过是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机中使用到的native方法服务。即如果当前线程执行的方法是Native类型的,这些方法就会在本地方法栈中执行。
总结一下,就JVM的设计规范,从使用用途角度JVM的内存大体的分为:线程私有内存区 和 线程共享内存区。
线程私有内存区在类加载器编译某个class文件时就确定了执行时需要的“程序计数器”和“虚拟栈帧”等所需的空间,并且会伴随着当前执行线程的产生而产生,执行线程的消亡而消亡,因此“线程私有内存区”并不需要考虑内存管理和垃圾回收的问题。
线程共享内存区在虚拟机启动时创建,被所有线程共享,是Java虚拟机所管理内存中最应该关注的和最大的一块。
好的有关JVM&GC今天我们就先介绍到这里,关于JVM内存模型是如何设计的?JVM又是如何进行内存管理(也就是垃圾回收)的?垃圾回收算法有哪些?目前常用的垃圾回收器又有哪些?我会在本系列的“下篇”跟您共同解答这些问题。
◆ ◆ ◆ ◆ ◆
如需转载请与小助手(微信号:creditease_tech)联系。发现文章有错误、对内容有疑问,都可以通过关注宜信技术学院微信公众号(CE_TECH),在后台留言给我们。我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!
注:文章封面原图素材来源于网络,若有侵权请留言删除。
⏬点击“阅读原文”查看更多技术干货