深入理解虚拟机

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mingyunxiaohai/article/details/86637196

JVM的结构

在这里插入图片描述

从上面的图可以看到,包含Class文件,类加载器(classloader),内存空间(分为方法区,java堆区,java栈区,本地方法区,垃圾收集),执行引擎,本地方法接口。

  • class文件就是java文件编译生成的
  • ClassLoader是加载.class文件的加载器
  • 方法区是用来存储被加载的类信息,常量,静态常量,静态方法等,(永远占据内存)。常量池在方法区内,收到方法区的限制,当常量池无法申请到内存的时候就会抛出OutOfMemoryError异常
  • 堆区是存放所有new出来的对象,是java虚拟机所管理的内存中最大的一块,被所有的线程共享,也是GC管理的主要区域
  • java栈区每个方法被调用的时候都会创建一个栈帧,用来存储局部变量,操作栈,动态链接,方法出口灯信息。当线程请求的栈深度大于虚拟机所允许的深度的时候会抛出StackOverflowError。当栈的扩展无法申请到足够内存的时候会抛出OutOfMemoryError异常
  • 本地方法区主要为native方法服务,线程隔离,跟java虚拟机栈类似。区别就是java虚拟机栈是用来执行java服务的,而本地方法栈是为执行native方法服务的
  • 程序计数器是线程隔离区域,每个线程都有自己的程序计数器,存储当前执行的字节码的行号,保证线程切换后能恢复到原来的执行位置。

Java代码的编译和执行过程

在这里插入图片描述
编译:

Java源代码是不能被机器识别的,需要经过编译器变异成JVM虚拟机可执行的.class字节码文件,在由解释器解释运行。把.java文件编译成.class文件。上面图其实就是javac命令根据不同的解析语法来解析java文件。

加载:

使用Classloader或者它的子类加载编译好的文件,Java中主要包含下面几中加载器

Bootstrap ClassLoader: 根ClassLoader,用C++实现,专门用来加载Java的核心API:$JAVA_HOME中jre/lib/rt.jar中所有class文件rt的意思是runtime

Extension ClassLoader: 加载Java扩展API jre/lib/ext中的类

App ClassLoader: 加载classpath目录下定义的class,也就是应用程序用到的ClassLoader。

Custom ClassLoader: 可以自定义的ClassLoader,可以继承这个ClassLoader然后自己实现。

类的加载过程如下

加载:把.class类的信息从文件中获取并且载入到JVM内存里
验证:检查读入的字节码是否符合JVM规范
准备:分配一个数据结构来存储类的信息,为静态变量分配内存,将其初始化为默认值。
解析:把这个类的常量池中的所有的符号引用改变成直接引用
初始化:执行静态初始化程序,把静态变量初始化成指定的值

执行:

JVM执行引擎执行字节码

垃圾回收

垃圾回收主要针对堆内存部分,按照分代算法划分,堆内存空间可以分为年轻代和老年代。

年轻代和老年代是根据对象的存活周期的不同划分的,年轻代短,老年代长

刚创建的对象会放到年轻代,年轻代的对象一般会在下一次垃圾回收的时候被回收,多次GC都没有被回收的对象就进入到了老年代

我们可以根据业务动态的调整年轻代和老年代的区域的大小。

垃圾收集算法找出哪些是垃圾

引用计数算法:

给每个对象分配一个引用计数器,每当有地方引用该对象的时候,引用计数器的值加一,当引用失效的时候,引用计数器减一,如果引用计数器为0说明该对象不在被引用了

缺点:如果两个对象之间互相引用,比如A引用B,B引用A,别的对象都没有引用A或者B,这时候他们俩其实是垃圾了,但是他们的引用计数器不为0,计数器也就无法通知GC回收他俩了。

可达性算法(java1.2之后):

通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始往下搜索,搜索走过的路程叫做引用链(Reference Chain),如果一个对象到GC Roots没有任何引用链接,说明这个对象不可用了。

Java中可以被称为GC Root的对象可以是一下几种:

(1)虚拟机栈(栈帧中的本地变量表)中引用的对象
(2)方法区中静态属性引用的对象
(3)方法区中常量引用的对象
(4)本地方法中Native方法引用的对象

上面两种算法中都有引用这个概念,Java中的引用有四种

(1)强引用,new出来的对象比如Object obj = new Object()的引用。垃圾回收器永远不会收集被强引用的对象。
(2)软引用,一些有用但不是必须的对象Java中使用java.lang.ref.SoftReference来表示,在内存不足的时候会回收改对象
(3)弱引用,非必须对象,当垃圾回收的时候无论内存是否充足,都会回收被弱引用挂你蓝的对象,Java中使用java.lang.ref.WeakReference这个类来表示
(4)虚引用,任何时候都可以被回收,Java中使用java.lang.ref.PhantomReference类表示。用的不多。

垃圾回收算法回收垃圾

1.标记清除算法

图片是从网上寻找的

从根节点开始遍历所有的引用,未被引用的对象标记为可回收对象,清除可回收对象

优点:不需要对象的移动,直接删除未被引用的对象,在对象较少的时候效率高

缺点:由于直接删除对象,会造成内存碎片

2.复制算法

图片是从网上寻找的
在这里插入图片描述
找一块空闲内存,从根节点开始遍历,把可以引用的对象复制到新的内存块中,然后清除原来内存块中的所有对象

优点:不会出现内存碎片

缺点:需要一块内存作为交换空间来移动对象,空间成本较高

3.标记整理算法

图片是从网上寻找的
在这里插入图片描述

从根节点开始遍历标记有引用的对象,未被标记的就是需要回收的,删除掉需要回收的对象之后,把所有对象压缩到内存的一端

优点:不会产生内存碎片

缺点:需要进行对象的移动,时间成本较高。

触发回收

  • Java虚拟机无法为新的对象分配内存空间了
  • 手动调用System.gc()方法(不推荐)
  • 低优先级的GC线程被运行时会执行GC

Dalvik VM 和 JVM的区别

  • 执行文件不同,一个是class,一个是dex
  • 类加载的系统与JVM区别较大
  • 可以同时存在多个Dalvik VM
  • Dalvik是基于寄存器的,而JVM是基于栈的

Dalvik VM 和 ART的区别

  • DVM使用JIT来将字节码转换成机器码,每次都要重新加载,效率低。
  • ART使用AOT的预编译技术,当应用安装的时候,就把字节码转换成机器码。
  • ART会占用更多的应用安装时间和存储空间,以空间换时间。

猜你喜欢

转载自blog.csdn.net/mingyunxiaohai/article/details/86637196