java虚拟机

Java虚拟机也就是我们通常说的JVM,学习Java就肯定要接触Java虚拟机。以前在论坛上见过写得好的博文,我摘录了一部分,再配上一些自己的话就写成了这个东西

编译流程

JVM字节码即为class文件,通过javac命令生成class文件,也就是说编译是把源代码装换成class文件,而编译最关键的地方在于编译器对词法、句法的分析

类加载器

其主要作用就是从class文件获取信息,载入JVM内存,如图:

java虚拟机

类加载器示意图

JVM内存管理

按逻辑可分为4大部分:

1.Java栈(线程独有): 主要作用是存放Java方法执行时的所有数据,由栈帧组成,一个帧代表一个方法的执行。每个方法从调用到执行完成就对应一个栈帧在虚拟机内的入栈到出栈

2.本地方法栈(线程独有): 专门为native方法服务(如C、C++方法)

3.方法区(全局共享): 存储被虚拟机加载的数据(如类信息、静态变量)

4.堆区(全局共享): 所有new创建的对象内存都在堆中分配。堆内存分新生代和老生代,新生代存储刚创建的对象。当内存不足时,虚拟机通过一系列算法将新生代移到老生代中,当新生代和老生代都满了,会导致内存溢出(OOM)

内存管理分为内存分配和内存释放,看一下上面的4个内存区域,可分为两部分,一部分是 全局共享 ,一部分是 线程独有

线程独有的自然是随线程启动而启动,随线程销毁而销毁,这部分内存由JVM主动管理,没GC什么事

全局共享的就不一样了,内存分配主要是由程序员显式的使用new关键字来触发的,至于new出来的这部分内存在哪分配,如何分配,是JAVA虚拟机来决定。而这部分内存的释放,则是由GC来管理的

垃圾回收(GC)

垃圾回收主要针对堆内存

垃圾收集算法

引用计数法: 被引用1次计数器就加1,没被引用时则被回收。假如两个对象相互引用,则起不到作用。已废弃

可达性算法(根搜索算法): 通过GC ROOT 对象开始搜索,回收不可达对象,存在强引用的宁可抛出OOM(内存溢出)也不会回收,弱引用会被回收

垃圾回收算法

标记—清除算法: 发现没有引用的对象,直接回收,会导致内存碎片过多

复制算法: 搜索扫描没有引用的对象,开辟新内存空间,将存活对象复制到新内存,旧内存直接清除,由于需多次交换内存空间,对象数量少时效率高,缺点是需要较大的内存空间

标记—整理算法: 在标记—清除算法的基础上,清除掉不存活的对象后,把后面存活对象搬运过来,使内存连续,解决内存碎片问题

分代收集算法: 基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。垃圾回收器(从J2SE1.2开始)都是使用此算法的

1. Young(年轻代)

年轻代分三个区。一个Eden区,两个 Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。

2. Tenured(年老代)

年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。

3. Perm(持久代)

用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class

那么何时触发垃圾回收呢?当年轻代或老年代满了,JVM无法为对象分配内存空间;调用System.gc(),但是请求不是命令,调不调用看虚拟机自身;程序运行时有一条低优先级GC程序

JVM、DVM和ART

由JVM又衍生出了DVM和ART,这里也简单介绍一下

DVM是基于JVM创造的,他执行dex文件而非class文件,类加载与JVM有较大区别,可同时存在多个DVM,JVM基于栈,DVM基于寄存器,寻址速度更快

ART可以认为是DVM的升级,ART采用了AOT预编译技术,APP安装时就完成了字节码转化为机器码,执行速度更快了,但ART会占用你更多的时间和空间,便利所带来的副作用就是占更多的时间和空间


分享到:


相關文章: