JVM系列文章
目录
前言
本次给大家介绍下JMM虚拟机内存模型中的一些概念。
先上一张图,给大家总体看下。
一、程序计数器
- 是当前线程所执行的字节码的行号指示器,指向虚拟机字节码指令的位置。
- 被分配了一块较小的内存空间。
- 针对于非Native方法:是当前线程执行的字节码的行号指示器。
- 针对于Native方法:则为undefined。
- 每个线程都有自己独立的程序计数器,所以,该内存是线程私有的。
- 这块区域是唯一一个在虚拟机中没有规定任何OutOfMemoryError情况的区域。
二、虚拟机栈& 本地方栈
虚拟机栈为执行Java方法服务的,是描述方法执行的内存模型。本地方法栈是为native方法服务的,就不做展开了。
- 栈是线程私有的内存空间。每次函数调用的数据都是通过栈传递的。在栈中保存的主要内容为栈帧。它的数据结构就是先进后出。
- 每当函数被调用,该函数就会被入栈,每当函数执行完毕,就会执行出栈操作。而当前栈顶,即为正在执行的函数。
- 每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、帧数据区等信息。
栈桢操作如下图所示:
三、堆
运行时数据区,几乎所有的对象都保存在java堆中。
- Java堆是完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显示地释放。
- 堆是垃圾收集器进行GC的最重要的内存区域。
- Java堆可以分为:新生代(Eden区、S0区、S1区)和 老年代。
- 在绝大多数情况下,对象首先分配在eden区,在一次新生代GC回收后,如果对象还存活,则会进入S0或S1,之后,每经历过一次新生代回收,对象如果存活,它的年龄就会加一。当对象的年龄达到一定条件后,就会被认为是老年代对象,从而进入老年代。
四、方法区
逻辑上的东西,是JVM的规范,所有虚拟机必须遵守的。
- 是JVM 所有线程共享的、用于存储类信息,例如:类的字段、方法数据、常量池等。
- 方法区的大小决定了系统可以保存多少个类。
- JDK8之前——永久代。
- JDK8及之后——元空间。
永久代
指内存的永久保存区域,主要存放Class和Meta(元数据)的信息,Class在被加载的时候被放入永久区域,它和存放实例的区域不同,GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。
- 如果系统使用了一些动态代理,那么有可能会在运行时生成大量的类,从而造成内存溢出。所以,设置合适的永久代大小,对于系统的稳定性是至关重要的。
- -XX:PermSize设置初始永久代大小。例如:-XX:PermSize=5m
- -XX:MaxPermSize设置最大永久代大小,默认情况下为64MB。例如:-XX:MaxPermSize=5m
元空间
在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。
- 元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用堆外的直接内存。因此,与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。
- -XX:MaxMetaspaceSize设置元空间默认初始大小。例如:-XX:MetaspaceSize=40m
- 设置最大元数据空间。例如:-XX:MaxMetaspaceSize=40m
总结
以上就是本次的分享,希望能给有需要的朋友帮助。