这里是修真院后端小课堂,每篇分享文从

【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】

八个方面深度解析后端知识/技能,本篇分享的是:

【jvm如何运行以及内存如何分配】

【修真院Java小课堂】jvm如何运行以及内存如何分配

 

开场语:

 

大家好,我是IT修真院北京分院第32期的学员廖友,一枚正直纯洁善良的Java程序员,今天给大家分享一下,修真院官网Java任务拓展中的知识点——jvm如

 

何运行以及内存如何分配

 

一、背景介绍:

jdk,jre,jvm的联系与区别

 

JDK: 

是java开发工具包,是Sun公司针对java开发人员的产品,jdk中包含jre,在jdk的安装目录下有一个jre的目录,里面有两个文件夹bin和lib,在这里

 

可以认为bin里面就是jvm,lib中是java工作需要的类库,而java和lib合起来就称为jre 

 

JRE: 

 是运行基于java语言编写的程序所不可缺少的运行环境,也是通过它,java的开发者才可以将自己开发的程序发布到用户手中,让用户使用,与大家

 

熟悉的jdk不同,jre是运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器,调试器)等,知识针对使用java程序的用户 

 

JVM: 

 就是我们常说的java虚拟机,它是整个java实现跨平台的最核心的部分,所有的java程序首先被编译为.class文件,这种类文件可以在虚拟机上运行

 

,也就是说class并不直接与机器的操作系统相对应。而是经过虚拟机间接的与操作系统交互,由虚拟机将程序解释给本地系统执行,只有jvm还不能将class

 

执行,因为在解释class的时候jvm需要调用解释所需要的类库lib,而jre包含lib类库,jvm屏蔽了具体操作系统平台的相关信息,使得java程序只需要生成

 

在java虚拟机上运行的目标代码。可以在多种平台(操作系统)上不加修改的运行 

 

JVM系统组成

类加载系统、执行引擎、运行时数据区

 

 

二、知识剖析:

 

1、程序计数器

 

程序计数器(Program Counter Register) 是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码

 

解释器工作时就是通过改变这个计数器的值来选取下一条执行字节码指令。

每条线程都有一个独立的程序计数器。

 

如果执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址。如果是native方法,计数器为空。

 

2、虚拟机栈

同样是线程私有,描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方

 

法出口等信息。一个方法对应一个栈帧。

局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址)。其中64位长度long 和 double占两个局部变量空间,其他

 

只占一个。

规定的异常情况有两种:1.线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;2.如果虚拟机可以动态扩展,如果扩展时无法

 

申请到足够的内存,就抛出OutOfMemoryError异常。

 

3、本地方法栈

和Java虚拟机栈很类似,不同的是本地方法栈为Native方法服务。

 

 

4、Java堆

是Java虚拟机所管理的内存中最大的一块。由所有线程共享,在虚拟机启动时创建。堆区唯一目的就是存放对象实例。

堆中可细分为新生代和老年代,再细分可分为Eden空间、From Survivor空间、To Survivor空间。

堆无法扩展时,抛出OutOfMemoryError异常

 

5、方法区

所有线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

当方法区无法满足内存分配需求时,抛出OutOfMemoryError

 

6、运行时常量池

它是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项是常量池(Const Pool Table),用于存放编译期生成的各

 

种字面量和符号引用。并非预置入Class文件中常量池的内容才进入方法运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比

 

较多的便是String类的intern()方法。

当方法区无法满足内存分配需求时,抛出OutOfMemoryError

 

7、垃圾收集(GC)

7.1 哪些内存需要回收

在运行时区域中,程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,而线程而灭;栈中的栈帧随着方法的进入和退出也有序的执行入栈出栈操作,且

 

栈帧的内存分配在编译期就已经确定了。因此这几个区域的内存分配和回收都具备确定性,在这几个区域不必多考虑回收的问题,因为方法结束或者线程结

 

束时,内存自然就跟着回收了

需要进行GC操作的是方法区和堆,因为这部分内存是动态分配的,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存可能

 

也不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象。

7.2 什么时候回收

引用计数算法:给对象中添加一个引用计数器,每当有引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再

 

被使用。

可达性分析算法:通过一系列的称为"GC Root"的对象作为起点,从这些节点开始向下搜索,搜素所走过的路径称为引用链(Reference Chain),当一个对

 

象到GC Root没有任何的引用链相连,就判定对象可以被回收。

7.3 如何回收

垃圾收集算法:标记-清除算法、复制算法、标记-整理算法、分代整理算法

垃圾收集器:Serial收集器、ParNew收集器、Parallel Scavenge收集器、Parallel old、Serial old、CMS、GI

 

8、内存分配原则

对象优先分配到Eden区

大对象直接进入老年区(需要连续内存空间的对象,例如很长的字符串以及数组)

长期存活的对象将进入老年代(对象年龄计数器,每GC一次,age+1)

动态对象年龄绑定

空间分配担保

 

 

三、编码实战

 

四、参考文献:

 

1https://www.cnblogs.com/zhouy...

 

[2]《深入理解Java虚拟机》

 

[3]http://www.importnew.com/1551...

 

五、更多讨论:

 

Q1:有没有可以检测jvm的工具

 

A1:检测jvm的工具有很多,jdk自己就带有很多个,如jps,jstart,jconsloe等,这些存放在bin目录下

 

Q2:Java程序可以运行在不同jvm中吗?

 

A2:可以的,比如安卓使用的是谷歌自己开发的davlik虚拟机,但我们同样可以编写Java程序在上面运行

 

Q3:jvm优化主要指那些方面

 

A3:最重要的就是堆的优化,因为这是存放对象的地方,是垃圾盛产地。

 

六、结束语:

 

今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~


用户bPbdDlb
422 声望36 粉丝