ghttps://blog.csdn.net/weixin_40701758/article/details/121756782?spm=1001.2014.3001.5501
程序计数器的主要作用是:
字节码解释器通过改变程序计数器来依次的读取指令,实现代码的流程控制
在多线程的情况下,程序计数器是用来记录线程的执行位置。
程序计数器的私有主要是为了线程切换后能够恢复到正确的执行的位置。
虚拟机栈:每个java方法在执行的时候,会创建一个栈帧来存储局部的变量表,操作数栈、常量池等信息。从方法的调用到执行完成的过程,就对应一个栈帧在java虚拟机栈中入栈和出栈的过程。
本地方法栈:虚拟机栈为执行java方法,本地方法栈是为虚拟机栈中使用到Native的方法,
为了保证线程中的局部变量不受别的线程所访问,本地方法栈和虚拟机栈是线程所私有的。
堆和方法区是线程所共享的资源,我们所知道的堆是进程中最大的一块内存的,主要是为了放新存放的对象的,方法区是为了存放已经加载的类的信息、常量、静态变量、及时的编译器后的代码的数据。
判断 一个对象是否存活的两种方式:
(1)引用计数法
所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一。当一个对象的引用计数器为零时,说明此对象没有被引用,也就是“死对象”,将会被垃圾回收.
引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,那么此时A,B对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法。
(2)可达性算法(引用链法)
该算法的基本思路就是通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。
在java中可以作为GC Roots的对象有以下几种:虚拟机栈中引用的对象、方法区类静态属性引用的对象、方法区常量池引用的对象、本地方法栈JNI引用的对象。
Java的每个类,在JVM中,都有一个对应的Klass类实例与之对应,存储类的元信息如:常量池、属性信息、方法信息
从继承的关系来看,类的元信息是存储在元空间中的,
普通的Java类在JVM中对应的是instanceKlass类的实例,再来说下它的三个字类
Java中的数组不是静态数据类型,是动态数据类型,即是运行期生成的,Java数组的元信息用ArrayKlass的子类来表示:
1、通过类的全限定名获取存储该类的class文件(没有指明必须从哪获取)
2、解析成运行时数据,即instanceKlass实例,存放在方法区
3、在堆区生成该类的Class对象,即instanceMirrorKlass实例
什么时候进行加载的呀?
主动使用时
1、new、getstatic、putstatic、invokestatic
2、反射
3、初始化一个类的子类会去加载其父类
4、启动类(main函数所在类)
(1)加载
加载时类加载的第一个过程,在这个阶段,将完成一下三件事情:
(2)验证
验证的目的是为了确保Class文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成以下四钟验证:
准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中。
(3)解析
该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。
(4)初始化
初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。