JVM内存与垃圾回收
Java虚拟机内存与垃圾回收
JVM的架构模型
Java编译器输入的指令流基本上是一种基于栈的指令集架构
,另一种指令集架构是基于寄存器的指令集架构
基于栈式架构的特点
- 设计和实现更简单,适用于资源受限的系统
- 避开了寄存器的分配难题:使用
零地址指令方式分配
- 指令流中的指令
大部分是零地址指令,其执行过程依赖于操作栈
。指令集更小,编译器容易实现 - 不需要硬件支持,
可移植性更好,更好实现跨平台
基于寄存器架构的特点
- 典型的应用是x86的二进制指令集:比如传统的PC和Android的Davlik虚拟机
- 指令集架构则完全依赖硬件,可移植性差
- 性能优秀和执行更高效
- 花费更少的指令去完成一项操作
- 在大部分情况下,基于
寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主
,而基于栈式架构的指令集却是以零地址指令为主
监控工具
- 终端输入:jconsole或者jvisualvm
JVM内存区
- 线程私有:程序计数器,虚拟机栈,本地方法栈
- 线程共有:Java堆,方法区
程序计数器
- 指向当前线程正在执行的字节码指令的地址(行号)
- 作用:因为Java是多线程的,为了确保在多线程情况下的程序正常执行
虚拟机栈
- 存储当前线程运行方法所需要的数据、指令、返回地址
- 大小设置:**-Xss 1M**
栈帧
- 每个方法在执行的同时都会创建一个栈帧,包含了这个方法自己的相关数据
- 划分为:
- 局部变量表
- 操作数栈
- 动态连接
- 返回地址
本地方法栈
- 本地方法栈是保存的是native方法的信息,当一个JVM创建的线程调用native方法后,JVM不在为其在虚拟机栈中创建栈帧,JVM只是简单的动态链接并直接调用native方法
Java堆
- -Xms,-Xmx,-Xmn
- 堆是非常重要的一部分,涉及到内存的分配(new 关键字,反射)与回收
- 几乎所有的对象都是在堆中分配
方法区
- 主要存储类信息,常量,静态变量,即时编译期编译后的代码
直接内存
- 所谓的零拷贝就是在这块区域
- 不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域
- 如果使用了NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作
- 这块内存不受java堆大小限制,但受本机总内存的限制,可以通过MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常
- 避免了在java堆和Native堆中来回的复制数据,能提高效率