JVM内存与垃圾回收

Java虚拟机内存与垃圾回收

JVM的架构模型

Java编译器输入的指令流基本上是一种基于栈的指令集架构,另一种指令集架构是基于寄存器的指令集架构

基于栈式架构的特点

  1. 设计和实现更简单,适用于资源受限的系统
  2. 避开了寄存器的分配难题:使用零地址指令方式分配
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器容易实现
  4. 不需要硬件支持,可移植性更好,更好实现跨平台

基于寄存器架构的特点

  1. 典型的应用是x86的二进制指令集:比如传统的PC和Android的Davlik虚拟机
  2. 指令集架构则完全依赖硬件,可移植性差
  3. 性能优秀和执行更高效
  4. 花费更少的指令去完成一项操作
  5. 在大部分情况下,基于寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主,而基于栈式架构的指令集却是以零地址指令为主

监控工具

  • 终端输入:jconsole或者jvisualvm

JVM内存区

  • 线程私有:程序计数器,虚拟机栈,本地方法栈
  • 线程共有:Java堆,方法区

JVM运行时数据区

JVM类代码
JVM运行代码图

程序计数器

  • 指向当前线程正在执行的字节码指令的地址(行号)
  • 作用:因为Java是多线程的,为了确保在多线程情况下的程序正常执行

虚拟机栈

  • 存储当前线程运行方法所需要的数据、指令、返回地址
  • 大小设置:**-Xss 1M**

虚拟机栈

栈帧

  • 每个方法在执行的同时都会创建一个栈帧,包含了这个方法自己的相关数据
  • 划分为:
    1. 局部变量表
    2. 操作数栈
    3. 动态连接
    4. 返回地址

本地方法栈

  • 本地方法栈是保存的是native方法的信息,当一个JVM创建的线程调用native方法后,JVM不在为其在虚拟机栈中创建栈帧,JVM只是简单的动态链接并直接调用native方法

Java堆

  • -Xms,-Xmx,-Xmn
  • 堆是非常重要的一部分,涉及到内存的分配(new 关键字,反射)与回收
  • 几乎所有的对象都是在堆中分配

方法区

  • 主要存储类信息,常量,静态变量,即时编译期编译后的代码

直接内存

JVM直接内存

  • 所谓的零拷贝就是在这块区域
  • 不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域
  • 如果使用了NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作
  • 这块内存不受java堆大小限制,但受本机总内存的限制,可以通过MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常
  • 避免了在java堆和Native堆中来回的复制数据,能提高效率

相关文章

Java反射和注解

Spring注解@NotNull等