JVM虚拟机--随笔

之前也看过很多资料,不过都自然而然的过滤了很多,下面就把自己对JVM初步的认识整理一下:

JVM全称(Java Virtual Machine),跟我们程序员接触最多的差不多就是它里面的栈、堆、方法区,还有一个比较重要的就是程序计数器

程序计数器是什么呢?

程序计数器是一块较小的内存空间,它的作用可看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是根据改变计数器的值来选定下一条需要执行的字节码指令,例如:分支、循环、跳转、异常处理、线程恢复。                                       在java多线程的情况下,线程的运行是根据处理器来分配时间的,在特定时刻处理器只能处理一个线程中的指令,而多个线程之间是来回切换运行的,每个线程都有一个属于自己的程序计数器,来保证线程切换后恢复到正确的运行位置。程序计数器记录的是正在运行的虚拟机字节码指令,而执行的不是java方法而是native方法时,则记录的是undefined,此区域在java规范中是一个唯一没有规定outOfMemoryError异常的区域。多个线程的程序计数器之间是互不影响的。像这种内存区域,我们称之为线程私有的内存。

栈是什么东东呢?

栈是描述java方法执行的内存模型。每个方法执行的时候都会创建一个栈帧,用来存储局部变量表、动态链接、方法出口等信息,鉴于此,所有它也是线程私有的。

局部变量表存储的是在编译期可知的基本数据类型(八大基本类型:byte/boolean/short/char/int/float/double/long)、对象引用(reference类型)、returnAddress类型。其中64位的long/double类型占用了两个局部变量空间(slot),其它类型的只占用一个局部变量空间。局部变量表的空间在编译期完成分配,方法运行期间不会改变局部变量表的空间大小。

此区域在java虚拟机规范中规定了两种异常:                                                                                                                            1.如果线程请求的栈深度大于虚拟机所允许的深度,则会抛出stackoverflowError异常。                                                             2.如果虚拟机栈可以动态扩展(大部分虚拟机栈目前都可以支持动态扩展),扩展时没有申请到足够内存时则会抛出OutOfMemoryError异常

堆是什么呢?

java堆是java虚拟机中最大的一块内存。它被所有线程所共享。它的唯一目的就是存放实例对象,所有的实例对象都在此分配内存。同时也是垃圾收集器主要管理的区域。

方法区是什么东东?

方法区与java堆一样,都是各线程所共享的内存区域。用于存放被java虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等数据

运行时常量池是方法区的一部分。Class文件中除了包含基本的类信息外还有一项信息是常量池(Constant pool table),用于存储编译器生成的字面量和符号引用,这部分内容将在类加载后存放到方法区中的运行时常量池。


我们在创建一个对象的时候,是怎样进行访问的呢?与以上所说的几个内存区又是怎样关联联系的呢?

Object o = new Object(); 在方法区运行改代码时,Object o这部分的语义将会作为一个reference类型的数据被反映到java栈的本地变量表中。而new Object()这部分语义将会被反映到java堆中,形成了一块存储Object类型所有实例数据值的结构化内存。在java堆中还生成了包含此对象类型数据的引用地址信息(必须有的),而此对象类型数据的实例值则在方法区中存放。

这里值得一说的是reference这个引用对象类型在java规范中并没有规定通过哪种方式去定位及访问到java堆中对象的位置,不同的虚拟机实现访问方式也是有所不同的,这两主流的访问方式有两种:     使用句柄;直接指针         

  第一种,通过句柄访问方式,reference引用类型中存有对象的句柄地址信息,在java堆中会划分出一块内存为句柄池,而句柄对象存有对象实例数据的地址信息及类型数据的地址信息,请看下图:


第二种,通过直接指针方式访问,在java堆对象布局中就需要考虑如何访问对象类型数据的相关信息,而reference中存储的就是对象实例数据的地址信息,请看下图:


既然有两种访问方式,那么问题来了,这两种使用哪种好呢?各自的特点是什么?

第一种:句柄访问,reference中存储的对象的句柄地址信息比较稳定,在对象被移动时(垃圾收集时,对象就会移动),改变的是句柄对象中对象实例数据的地址信息,而reference不会改变。

第二种:直接指针访问,速度快效率高。因为reference中存储的直接是对象的地址信息,少了一步定位,即节省了一次指针定位的时间开销,由于对象的访问在java中是非常频繁的,所有积少成多也是非常可观的,大大节省了执行成本。例如:Sun HotSpot


今天就说这么多,后续如果有进一步的认识会再次跟大家一块分享,,同时也希望大家如果有不同的见解能够提出来,共同进步!得意得意得意


猜你喜欢

转载自blog.csdn.net/Zhang_521521/article/details/80539568