什么是Java虚拟机?
Java虚拟机是一个可以执行Java字节码(Java 源文件被编译成能被 Java 虚拟机执行的字节码文件( .class ))的虚拟机进程。
Java 被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。
但是,跨平台的是 Java 程序(包括字节码文件),,而不是 JVM。JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM 。
JVM内存区域模型
JVM 内存区域基本上由4个区域组成:
- 类加载器:在JVM启动时或者类运行时,将需要的class加载到JVM中。
- 运行时数据区:将内存划分成若干个区以模拟实际机器上的存储、记录和调度功能模块。
- 执行引擎:负责执行class文件中包含的字节码指令,相当于实际机器上的CPU。
- 本地方法调用:执行C/C++实现的本地方法的代码,并返回结果。
Java 运行时数据区域
程序计数器
Java 线程私有,类似于操作系统里的 PC 计数器,它可以看做是当前线程所执行的字节码的行号指示器。
- 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器值则为空(Undefined)。
- 此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。
Java虚拟机栈
Java线程私有,虚拟机栈描述的是 Java 方法执行的内存模型:
- 每个方法在执行的时候,都会创建一个栈帧用于存储局部变量、操作数、动态链接、方法出口等信息。
- 每个方法调用都意味着一个栈帧在虚拟机栈中入栈到出栈的过程。
本地方法栈
和 Java 虚拟机栈的作用类似,区别是该区域为 JVM 提供使用 Native 方法的服务。
Java堆
所有线程共享的一块区域,垃圾收集器管理的主要区域。
- 目前主要的垃圾回收算法都是分代收集算法,所以 Java 堆中还可以细分为:新生代和老年代;再细致一点的有 Eden 空间、From Survivor 空间、To Survivor 空间等,默认情况下新生代按照 8:1:1 的比例来分配。
- 根据 Java 虚拟机规范的规定,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘一样。
元数据(方法区)
各个线程共享的一个区域,用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。
运行时常量池
是元数据的一部分,用于存放编译器生成的各种字面量和符号引用。
直接内存
并不是虚拟机运行时数据的一部分。JDK1.4引入了NIO,它可以使用Native函数库直接分配堆外内存。直接内存的分配不会受到Java堆大小的限制,但是会受到本机内存的限制。也可能导致OutOfMemoryError
出现。
JVM内存区域的详细介绍可以看这篇深入理解JVM之Java内存区域
Java 内存堆和栈区别?
- 栈内存用来存储基本类型的变量和对象的引用变量;堆内存用来存储Java中的对象,无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。
- 栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存;堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
- 如果栈内存没有可用的空间存储方法调用和局部变量,JVM 会抛出 java.lang.StackOverFlowError 错误;如果是堆内存没有可用的空间存储生成的对象,JVM 会抛出 java.lang.OutOfMemoryError 错误。
- 栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。-Xss 选项设置栈内存的大小,-Xms 选项可以设置堆的开始时的大小。
当然,如果你记不住这个些,只要记住如下即可:
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。
Java 对象创建过程?
JAVA 对象创建的过程,如下图所示:
有哪些 OutOfMemoryError 异常?
- Java 堆溢出
- 虚拟机栈和本地方法栈溢出
- 元数据的内存溢出
- 运行时常量池溢出
垃圾收集器与内存分配策略
垃圾回收算法有哪些?
垃圾收集器有哪些?
判断对象死亡的2种常用方法?
什么是新生代 GC 和老年代 GC?
虚拟机性能监控与故障处理工具
JDK 的命令行工具有哪些可以监控虚拟机?
JDK 的可视化工具有哪些可以监控虚拟机?
如何排查线程 Full GC 频繁的问题?
虚拟机类加载机制
什么是类加载器?
类加载器(ClassLoader),用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。
类加载器,负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。
- 每个这样的实例用来表示一个 Java 类。通过此实例的 Class#newInstance(…) 方法,就可以创建出该类的一个对象。
- 实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。