JVM结构及GC机制

GC主要用于管理 JVM 的 堆区,所以先介绍一下 JVM的内存分配
安卓启动优化


JVM主要包括:程序计数器,Java虚拟机栈区,本地方法栈,堆区,方法区
在Java中,对象实例都是在堆上创建。
方法区(静态成员区):1 类(class) 2 静态变量(static变量) 3 静态方法 4 常量 5 成员方法,都存储在方法区
堆和方法区都是线程共享的。

JVM结构及GC机制


1 程序计数器( Program Counter Register)

程序计数器是一块小的内存空间,它是当前线程执行字节码行号指示器字节码解释工作器就是通过改变这个计数器的值,来选取下一条需要执行的指令。它是线程私有的内存,也是唯一 一个 没有 OOM异常的区域。

2 Java虚拟机栈区( Java Virtual Machine Stacks)

是通常所说的栈区,它描述的是Java方法执行的内存模型,每个方法被执行的时候,都创建一个帧栈(Stack Frame),用于存储局部变量表,操作数栈,动态链接,方法出口等。每个方法被调用完成,相当于一个帧栈在虚拟机栈中,从入栈到出栈的过程。此区域是线程私有内存,可能抛出两种异常:

线程请求的栈深度,大于虚拟机允许的深度,,抛出 StackOveflowError异常
虚拟机在扩展栈时,无法申请到足够的内存空间,抛出OOM(OutOfMemoryError)异常

这里把异常分为两种情况,看似更加严谨,但却存在一些互相重叠的地方:当栈空间无法继续分配时,到底是内存太小,还是已使用的栈空间太大,其本质上只是对同一件事情的两种描述 — 详见 JVM书53页

3 本地方法栈( Native Method Stacks)

本地方法栈与虚拟机栈发挥的作用非常相似,区别就是虚拟机栈为 虚拟机执行Java方法,本地方法栈是为 虚拟机使用到的 Native方法 服务

4 堆区( Heap)

所有对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还可以细分为新生代,老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为所有线程共享区域。当堆中没有足够内存完成实例分配时,会抛出OOM异常。
根据对象的使用频率,不断的从新生代往老年代转移,频率越高,转移几率越大,频率不高,会在 Eden中就被回收。
新生代 Eden区和两个 Survivor区的比例大概是 8:1:1
JVM结构及GC机制

JVM结构及GC机制
5 方法区( Method Area)

方法区与堆区一样,是各个线程共享的区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译后的代码等数据。GC在这个区域很少出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,所以也有称这个区域为永久代(Permanent Generation)的。当方法区无法满足内存分配时,抛出OOM异常。
虽然 Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java堆 区分开来

6 运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用

运行时数据区,即我们说的内存
JVM结构及GC机制

黄色代表线程共享,蓝色代表非线程共享
JVM结构及GC机制
JVM结构及GC机制