手记

jvm内存模型-深入理解jvm

  最近学习了周志明老师的《深入理解Java虚拟机》,收获颇多,留下一些学习笔记,供以后复习用。

  JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创建,在JVM退出的时候销毁。而其他的数据依赖于每一个线程,在线程创建时创建,在线程退出时销毁。

一.重点笔记

线程共享区域:java堆  方法区。

线程私有区域:jvm栈  本地方法栈  程序计数器

二.各个区域作用:

java堆

  java堆是jvm内存管理中最大的一块,线程共享。堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”。在jvm启动的时候创建。此区域唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。java堆细分为新生代和老年代,新生代又分为Eden空间、From Survivor空间、To Survivor空间,其大小在HotSpot虚拟机中默认比例为8:1:1,新生代中垃圾回收算法为复制算法,老年代中采用的GC算法为标记-清除算法或者标记-整理算法(GC算法会在下一篇文章中具体讲解)。在进行垃圾回收的时候新生代GC又叫minor GC,老年代GC可以设置内存容量达到百分比的多少的时候进行GC,老年代的GC又叫Full GC或者Major GC,minor GC时间短,频率高,而Full GC时间长,频率低。

方法区

  很多人都更加愿意把方法区成为“永久代”,在jdk8中已经将永久带移除了,用新出现的元空间(Metaspace)来代替原来的永久带,线程共享,是用来存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。简单说方法区用来存储类型的元数据信息,一个.class文件是类被java虚拟机使用之前的表现形式,一旦这个类要被使用,java虚拟机就会对其进行加载、连接(验证、准备、解析)和初始化。而加载后的最终产品位于堆或方法区的class对象,改对象封装了一段特定的数据结构,供程序员提供访问接口。这个区域很少进行垃圾回收,回收目标主要是针对常量池的回收和对类型的卸载。

  运行时常量池(Runtime Constant Pool):它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到常量池中。运行时常量是相对于常量来说的,它具备一个重要特征是:动态性。当然,值相同的动态常量与我们通常说的常量只是来源不同,但是都是储存在池内同一块内存区域。Java语言并不要求常量一定只能在编译期产生,运行期间也可能产生新的常量,这些常量被放在运行时常量池中。这里所说的常量包括:基本类型包装类(包装类不管理浮点型,整形只会管理-128到127)和String(也可以通过String.intern()方法可以强制将String放入常量池)。

jvm栈

  线程私有,它的生命周期与线程相同。虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

  局部变量表:一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译成Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。局部变量表的容量以变量槽(Slot)为最小单位,32位虚拟机中一个Slot可以存放一个32位以内的数据类型(boolean、byte、char、short、int、float、reference和returnAddress八种)。

  操作数栈:和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。但是和前者不同的是,它不是通过索引来访问,而是通过标准的栈操作——压栈和出栈—来访问的。虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。

  动态连接:虚拟机运行的时候,运行时常量池会保存大量的符号引用,这些符号引用可以看成是每个方法的间接引用。如果代表栈帧A的方法想调用代表栈帧B的方法,那么这个虚拟机的方法调用指令就会以B方法的符号引用作为参数,但是因为符号引用并不是直接指向代表B方法的内存位置,所以在调用之前还必须要将符号引用转换为直接引用,然后通过直接引用才可以访问到真正的方法。如果符号引用是在类加载阶段或者第一次使用的时候转化为直接应用,那么这种转换成为静态解析,如果是在运行期间转换为直接引用,那么这种转换就成为动态连接。

本地方法栈

  本地方法栈和JVM栈非常相似,它们之间的区别不过是jvm栈是为执行java方法服务,而本地方法栈是为jvm使用到对的本地方法服务。HotSpot虚拟机中直接把本地方法栈和JVM栈合二为一了。

程序计数器

  程序计数器是一块较小的内存空间,线程私有。它可以看作是当前线程所执行的字节码的行号指示器。在jvm的概念模型里,字节码解释器工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

三.总结:

参考资料:

https://www.cnblogs.com/lifescolor/p/5481588.htmlhttps://blog.csdn.net/u012152619/article/details/46968883



作者:Swen_9826
链接:https://www.jianshu.com/p/06b329bf4baa


0人推荐
随时随地看视频
慕课网APP