Java 虚拟机简记

119 阅读4分钟

JVM (Java Virtual Machine)

JVM是什么

jvm本身是一个进程,用于运行java程序,该进程只支持一个java程序。

JVM生命周期

当运行一个java程序,一个JVM实例便诞生了,一个简单的 hello world 程序,通常会包含一个用户线程(主线程)及一些守护线程(垃圾回收线程[gc],终结器线程等),当用户线程全部执行完毕,或调用 System.exit() 方法结束了唯一的用户先,虚拟机实例便结束了。

运行时数据区

Java 虚拟机定义了在程序执行期间使用的各种运行时数据区域。其中一些数据区是在 Java 虚拟机启动时创建的,只有在 Java 虚拟机退出时才会被销毁。其他数据区域是每个线程。每个线程的数据区域在创建线程时创建,并在线程退出时销毁。

在这里插入图片描述

// javap 命令可以查看.class 字节码,
javap -v .\xxx.class

javap 命令查看 .class 文件,会发现有一个 Constant pool: ,这里的常量信息,会在.class被加载的时候,复制到运行时常量池。

在这里插入图片描述

方法区

jvm在内部如何存储类型信息,这由具体设计者决定的。

运行时常量池

在这里插入图片描述

如上图所示,其中定义的信息都会进入到常量池,

这里有两个常见的问题:

1.String 对象 String str = “hello”; String str = new String(“hello”); 两种创建方式的区别。

String str = “hello”;最多创建一个String对象,最少不创建String对象。如果常量池中,已经存在“hello”,那么str直接引用,此时不创建String对象,否则,先在常量池先创建“hello”内存空间,再引用。

String str = new String(“hello”);最多创建两个String对象,至少创建一个String对象。new关键字:绝对会在堆空间创建内存区域。

2.Java Integer(-128~127)值的 ==equals 比较。

  	// -128~127 返回的是 IntegerCache 中的对象
	public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

用于存储对象以及数组,注意 static 修饰的变量会进入方法区。

虚拟机栈

一个线程对应私有的一个虚拟机栈,它保存局部变量和部分结果,并在方法调用和返回中发挥作用。

本地方法栈

一个线程对应私有的一个本地方法栈,ava 虚拟机的实现可以使用传统的堆栈,通俗地称为“C 堆栈”,以支持native方法(以 Java 编程语言以外的语言编写的方法)。本地方法栈也可以被 Java 虚拟机指令集的解释器实现使用,例如 C 语言。不能加载native 方法并且本身不依赖传统栈的 Java 虚拟机实现不需要提供本地方法栈. 如果提供,本机方法堆栈通常在创建每个线程时为每个线程分配。

程序计数器

一个线程对应一个私有的程序计数器,我们知道,用于存放下一条指令所在的地址。这里地址可以是一个本地指针,也可以是方法中相对于该方法起始指令的偏移量。

如果线程当前正在执行的方法是native,则 Java 虚拟机的pc 寄存器的值是未定义的。

垃圾回收(GC)

垃圾回收的算法有很多种,如引用计数算法可达性分析算法标记-清除算法(Mark-Sweep)复制算法(Copying)标记-压缩算法(Mark-Compact) 。虚拟机里用的是哪种算法并不固定。

使用 jconsole.exe 应用,可以便捷的查看 jvm 的各项信息。

在这里插入图片描述

内存泄露

内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

通俗点,就是对象用完了,但是因为仍有对象持有他的引用没办法回收他的内存,导致空间浪费了,如果一直浪费,收不回去就会OOM。

如下图所示,当我们不需要 Object 之后, 我们想让GC把它收走,就得让它满足GC条件,没有引用链接它。

分析引用持有时有个要点,就是匿名内部类和非静态内部类会持有外部类的引用。 在这里插入图片描述

还有,我们在调用他人提供的类库,框架时,如IO,Socket等等,须注意规范使用即用完之后及时调用他们提供的关闭,注销方法,防止内存泄露。

在安卓中,handle ,context,静态view,webView是造成内存泄露的重灾区。

参考资料

  1. 深入Java虚拟机 Bill Venners著
  2. www.cnblogs.com/icyfumanix/…
  3. docs.oracle.com/javase/spec…
  4. www.javatpoint.com/jvm-java-vi…