JVM中内存区可以根据受访问权限的不同定义为线程共享线程私有两大类。以下是我学习的一些笔记,这些知识是基于java7的,java7以后的版本会有点不同,但是大同小异,核心是不会变的。

一、线程私有内存区

1、PC寄存器(PC计数器)

  • 如果线程执行的方法是个java方法,那么pc寄存器就会存储正在执行的字节码指令的地址 ,如果是native方法,这时候pc寄存器就是空(undefined);
  • 所谓多线程在一个特定的时间内只会执行其中某一个线程方法,cpu会不断作任务切换,所以为每一个线程都分配一个pc寄存器
  • JVM字节码解析器通过改变寄存器的值来明确下一条该执行什么指令;
  • pc寄存器是唯一一个没有明确规定要抛出OutofMemeryError的运行时内存区。

2、Java栈

  • 线程私有,生命周期与线程的周期保持一致
  • 用于存储栈帧,栈帧中存储局部变量表(各类原始数据类型,对象引用以及returnAddress类型);
  • 可被允许实现成固定大小的内存或者可动态扩展的内存大小,如果被设定为固定内存,一旦线程请求分配的栈容量超过jvm所允许的最大值,则会抛出StackOverFlowError,反之会抛出一个OutOfMemoryError。

3、本地方法栈

  • 用于支持本地方法,比如C/C++的执行的区域地址。
    二、线程私有内存区

1、堆区

  • 堆区是用于存储对象实例的内存区,是GC执行垃圾回收的重点区域,是线程共享的;
  • 堆的大小在jvm启动时就已经设定好,通过-Xmx设置最大内存,-Xms设置起始内存,一旦超过“Xmx”,抛出内存溢出错误;
  • 内存空间不连续。

2、方法区

  • 线程共享;
  • 存储每一个java类的结构信息,如:运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容及类,实例,接口初始化时需要的特殊方法等;
  • 包含在java堆内,物理上属于堆的一部分;
  • 内存空间不连续;
  • 通过“-XX:MaxPermsize”制定最大内存,超过则抛出OOM错误。

3、运行时常量池

  • 属于方法区的一部分;
  • 当类加载器成功为一个类或接口装载进jvm后,就会创建与之对应的运行时常量池所需内存,如果超过方法区提供的最大值,会抛出OOM错误。

4、性能监控区

  • Prims模块的子模块PERF;
  • 用于监控jvm内部的perf data计数器,是jvm提供的一块内存共享区,专供外部程序访问这块区域的Perf-Data,实现外部程序监控Jvm的性能指标。