Java虚拟机内存模型
Java虚拟机将内存数据分为程序计数器、虚拟机栈、本地方法栈、Java堆和方法区等部分
程序计数器
一块很小的内存空间,用于记录下一条要运行的指令
虚拟机栈
Java虚拟机栈也是线程私有的空间,它和Java线程在同一时间创建,它保存方法的局部变量、部分结果、参与方法的调用和返回
两种和栈空间有关的异常:
- StackOverflowError: 如果线程在计算的过程中,请求的栈深度大于可用栈的深度,则抛出StackOverflowError
- OutOfMemoryError: 如果Java栈可以动态扩展,而扩展的过程中,没有足够的内存空间来支持栈的扩展,则抛出OutOfMemoryError
本地方法栈
功能和虚拟机栈相似,但本地方法栈不是由Java实现的,而是使用C实现
Java堆
几乎所有的对象和数组都是在堆中分配空间的。
java堆分为新生代和老年代:
新生代:用于存放刚刚产生的对象和年轻的对象,新生代又可分为eden、survivor space0(s0或者from space)和survivor space1(s1或者to space)
- eden: 伊甸园,对象刚刚建立时会存放在这里
- s0和s1为survivor空间,译为幸存者,也就是存放在这里的对象至少经历了一次垃圾回收,并得以幸存
老年代:如果对象一直没有被回收,生存得足够长,年老的对象就会被移入老年代(如果幸存区的对象到了指定的年龄仍未被回收,则会进入老年代[tenured])
方法区
与堆空间类似,也是被JVM中所有的线程共享,方法区保存的信息是类的元数据
方法区中最为重要的是类的类型信息、常量池、方法信息。
- 类型信息:类的完整名称、父类的完整名称、类型修饰符(public/protected/private)和类型的直接接口类表
- 常量池:包括这个类的方法、域等信息所引用的常量信息
- 域信息:包括域名称、域类型和域修饰符
- 方法信息:包括方法名称、返回类型、方法参数、方法修饰符、方法字节码、操作数栈和方法桢栈的局部区大小以及异常表
在HotSpot虚拟机中,方法区也称为永久区,是一块独立于Java堆的内存空间。虽然叫做永久区,同样也是可以被GC回收的。通常主要从两个方面:一是GC对永久区常量池的回收;二是永久区对类元数据的回收