java8 jvm gc_JVM层GC调优(上)

JVM内存结构简介(jdk1.8)

JVM层的GC调优是生产环境上必不可少的一个环节,因为我们需要确定这个进程可以占用多少内存,以及设定一些参数的阀值。以此来优化项目的性能和提高可用性,而且这也是在面试中经常会被问到的问题。

想要进行GC调优,我们首先需要简单了解下JVM的内存结构,Java虚拟机的规范文档如下:

在介绍JVM内存结构之前,我们需要先知道运行时数据区这样的一个东西,它与JVM的内存结构有着一定的关联。不过它属于是一个规范,所以与JVM内存结构是有着物理上的区别的。运行时数据区如下:

java8 jvm gc_JVM层GC调优(上)_第1张图片

1.程序计数器(Program Count Register,简称PC Register):

JVM支持多线程同时执行,每一个线程都有自己的PC Register。当每一个新线程被创建时,它都将得到它自己的PC Register。线程正在执行的方法叫做当前方法。如果执行的是Java方法,那么PC Register里存放的就是当前正在执行的指令的地址,如果是native方法(C/C++编写的方法),则是为空。此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

2.虚拟机栈(JVM Stacks):

Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同。虚拟机描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程,实际上就是所谓的线程堆栈。

局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址)。其中64位长度 long 和 double 占两个局部变量空间,其他只占一个。

该区域中规定的异常情况有两种:1.线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;2.如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,就抛出OutOfMemoryError异常。

3.堆Heap:

Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。堆中可细分为新生代和老年代,再细分可分为Eden空间、From Survivor空间、To Survivor空间。堆无法扩展时,会抛出OutOfMemoryError异常。

4.方法区(Method Area):

方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的是与Java堆区分开来。

当方法区无法满足内存分配需求时,抛出OutOfMemoryError

5.运行时常量池(Run-Time Constant Pool):

如上图所描述的一样,它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项是常量池(Const Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后被放入方法区的运行时常量池中存储。并非预置入Class文件中常量池的内容才进入方法运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

同样的,当方法区无法满足内存分配需求时,也会抛出OutOfMemoryError

6.本地方法栈(Native Method Stacks):

本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。

了解了运行时方法区规范后,我们接下来看看JVM的内存结构图:

java8 jvm gc_JVM层GC调优(上)_第2张图片

如上图,可以看到JVM内存被分为了两大区,非堆区用于存储对象以外的数据:

Metaspace:存放Class、Package、Method、Field、字节码、常量池、符号引用等等

CCS:这个区域存放32位指针的Class,也就是压缩类空间,默认关闭,需要使用JVM参数开启

CodeCache:存放JIT编译后的本地代码以及JNI使用的C/C++代码

而堆区则用于存储对象相关数据:

Young:新生代,存放新的或只经过几次Minor GC的对象

Eden:存放最新创建的对象,一些较大的对象则会特殊处理

S0/S1:当对象经过第一次Minor GC后,如果仍然存活,就会存放到这里。需要注意的是,S0和S1区域在同一时间上,只有其中一个是有数据的,而另一个则是空的。

Old:老年代,当S0或S1区域存满对象了,就会把这些对象存放到这个old区域中

你可能感兴趣的:(java8,jvm,gc)