Java第二章小结

参考博客学习https://blog.csdn.net/chenkaibsw/article/details/80812453

1.程序计数器

它是当前所执行的字节码的行号指示器,字节码解释器工作时就是通过改变计数器的值来选择下一条需要执行的字节码指令、分支、跳转、循环等基本功能都要依赖它来实现。每一个线程都有一个独立的程序计数器,各线程间的计数器互补影响

2.Java虚拟机栈

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

局部变量表:是一组变量值存储空间,用于存放方法形参和方法内部定义的局部变量。其中存放的数据的类型是编译期

http://xtu-tja-163-com.iteye.com/blog/775987

局部变量表:

是以字节为单位,从0开始计数的数组,类型short、byte和char的值在存入数组前要被转换成int值,而long和double在数组中占据了连续的两项,在访问局部变量中的long或double时,只需取出连续两项的第一项的索引值即可。

扫描二维码关注公众号,回复: 1887859 查看本文章

runInstanceMethod局部变量区第一项是个reference(引用),它指向的就是对象本身的引用,也就是我们常用的this,但是在runClassMethod方法中,没有这个引用,那是因为runClassMethod是个静态方法。
操作数栈:


操作数栈的最大深度在编译的时候就确定了,32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为2.当一个方法开始执行时,它的栈是空的,在方法的执行过程中,会有各种各样字节码指令(比如:加操作、赋值操作等)向操作栈中写入和提取内容,也就是入栈和出栈操作。

Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所指的"栈就是操作数栈",因此我们也称Java虚拟机是基于栈的,而Android虚拟机是基于寄存器的。

基于栈的指令集最主要的优点是可移植性强,主要的缺点是执行的速度相对会慢些;而由于寄存器由硬件直接提供,所以基于寄存器指令集最主要的优点是执行速度快,主要的缺点是可移植性查。

3.动态连接

每个栈帧都包含一个执行运行时常量池(在方法区中)中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用,一部分会在类加载阶段或第一次使用的时候转化为直接引用,称为静态解析,另一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

自己的理解:如下图所示,每个栈帧都包含一个执行时常量池中该栈帧所属方法的引用,例如这个栈帧是f(),而f()中使用到ff()??????????????


4.方法返回地址:

当一个方法执行后,有两种方式退出该方法:执行引擎遇到了任意一个方法返回的字节码指令或遇到了异常,并且该异常没有在方法体内得到处理。无论采用何种退出方式,在方法退出后,都需要返回到方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说方法正常退出时,调用者的PC计数器的值就可以作为返回地址。

方法退出的过程中实际上等同于把当前栈帧出栈,因此退出时可能的操作有:恢复上层方法的局部变量表和操作数栈,如果有返回值,则把它压入调用者的操作数栈中,调用PC计数器的值以指向方法调用后面的一条指令。

本地方法栈:

本地方法栈和虚拟机栈的作用相似,只是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为使用的本地操作系统方法服务。

Java堆:

Java堆时所有线程共享的一块内存区域,几乎所有的对象和数组都在这里分配内存。Java堆是垃圾收集器的主要管理区域,因此很多时候也被成为"GC"堆。

方法区:

方法区是各线程共享的内存区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。该区域的内存回收目标主要针对废弃常量和无用类的回收。运行时常量池是方法区的一部分。Class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项是Class文件常量池,用于存放编译器生成的各种字面量和符号引用,这部分将在类加载后存放到方法区的运行时常量池中。运行时常量池相对于Class文件常量池的具有一个重要特征是具有动态性,并不是预置入Class文件中的常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,开发人员用比较多的是String类的intern()方法。

Java内存泄漏:是指分配出去的内存没有回收回来,由于失去了对该内存区域的控制,因而造成了资源的浪费。Java一般不会有内存泄漏,因为垃圾收集器自动回收垃圾,但这也不绝对,当我们new了对象,并保存了其引用,但是后面一直没有用到它,而来及收集器又无法回收它,此时就会造成内存泄漏。

内存溢出:程序所需的内存超过了系统所能分配的内存。

对象实例分析:

object obj = new object();

这行代码会涉及Java栈、Java堆、方法区三个最重要的内存区域。obj作为引用类型放在Java栈的局部变量表中,而Java堆中保存实例化对象。方法区中保存包含能查找到此对象类型数据的地址信息(如对象类型、父类、实现的接口、方法等)

HotSpot中使用直接指针访问对象的方式。

课本44页:对象的创建过程:

检查这个指令的参数是否能在常量池(字符串常量池)中定位到一个类的符号引用,并检查这个符号引用是否已被加载、解析和初始化过。

指针碰撞和空间列表,CMS收集器采用的空闲列表,Serial、ParNew采用的是指针碰撞。(CMS会导致内存不规整,Serial、ParNew使用复制算法、标记—整理算法,所以内存规整)

分配内存,修改指针,并发情况下不是线程安全的。

虚拟机将分配到的内存空间都初始化为零。这样可以保证对象的实例字段在Java代码中不赋初始就直接使用,程序能访问这些字段的数据类型所对应的零值。

虚拟机对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头中。

执行new指令之后接着执行<init>方法,把对象按照程序员的意愿初始化。


猜你喜欢

转载自blog.csdn.net/chenkaibsw/article/details/80833688