JVM是什么?Java Virtual Machine(Java虚拟机)的缩写,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收,堆 和 一个存储方法域。是不是总听说一句话,说什么java是一次编译到处运行,为什么可以到处运行呢?关键就在于JVM的处理,一个java文件到最后运行的过程是这样的:
Java源文件>编译器>字节码文件>JVM>机器码
由图上可以看出,不同的java虚拟机转成的机器码也不同,最后可以在不同的系统上执行,由此来实现一次编译到处运行。接着我们再来看看JVM的体系结构是怎样的:
类加载子系统:就是把class文件加载到方法区里
执行引擎:将字节码转换成机器码并执行输出执行结果
寄存器:存储每个线程下一步将执行的JVM指令,native方法寄存器中不存储任何信息。
本地方法(栈,接口,库):都是非Java的一堆东西,比如微软的C系列,java程序调用非java程序时用的。
方法区:在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代,各个线程的共享区域,主要存放类信息、静态变量、常量、接口、类的权限定名、字段等,在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息
栈:JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。
堆:线程共享的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,也就是Java垃圾收集器管理的主要区域GC堆
垃圾收集器:垃圾收集器就是内存回收的具体实现
讲到垃圾收集,就不得不讲垃圾收集算法,垃圾回收也是经常被大家提到的研究的东西,小编也粗略的分享下自己的见解,前面咱们提到了,什么寄存器,栈,本地方法栈啥的都是线程独享的部分,当线程被销毁的时候这些东西也会被回收,没啥毛病,问题是,堆和方法区呢,他们是各个线程共享的部分,线程没了,这些东西里面肯定有一些没用的东西来占着内存,内存又不是无限大的,如果不释放掉,早晚要出事,所以垃圾回收应运而生。
细心的小伙伴又发现问题了,咋确定对象是否要回收呢?
第一种叫什么引用计数算法,就是给对象中添加一个引用计数器,每当一个地方应用了对象,计数器加1;当引用失效,计数器减1;当计数器为0表示该对象已死、可回收。但是它很难解决两个对象之间相互循环引用的情况。
第二种叫可达性分析算法,通过一系列称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(即对象到GC Roots不可达),则证明此对象已死、可回收。(Java中可以作为GC Roots的对象包括:虚拟机栈中引用的对象、本地方法栈中Native方法引用的对象、方法区静态属性引用的对象、方法区常量引用的对象)
对象Object5、Object6和Object7之间虽然彼此还有联系,但是它们到GC Roots是不可达,所以被判定为可回收对象。
JVM对象的引用分为了四种类型:
- 强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收,中断强引用与对象之间的联系,可以显示的将强引用赋值为null)
- 软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)用java.lang.ref.SoftReference类来表示软引用
- 弱引用:在GC时一定会被GC回收,java.util.WeakHashMap这么一个key为弱引用的Map。
- 虚引用:虚引用只是用来得知对象是否被GC,必须和引用队列一起使用
好了这期差不多了,先消化一下,咱们下期讲垃圾收集的几种算法,和堆内存的各代划分及转换规则,大家想获取更多知识的,可以继续关注公众号,不定时推送。分享了这么牛逼的知识,还不请小编喝个水吗,哈哈哈,欢迎土豪直接赏赞,谢谢,您的支持就是小编最大的动力。