JVM内存管理,虚拟机堆栈的理解

前言:C或者C++的内存申请和销毁需要程序员自己控制,很容易内存泄漏和内存溢出且出现问题查找困难。Java在内存管理的优势在于jvm自己申请和销毁内存,不需要程序员关注内存问题,更专注于业务逻辑。那为什么我们还需要理解JVM的内存管理机制和原理呢?第一、作为有追求的程序猿应该追根刨底,做到知自知彼;第二、当内存管理成为系统性能瓶颈时或者出现内存泄漏、内存溢出问题,程序猿只有了解JVM的内存原理才能够去优化和查找内存问题。


先上图,给各位同学有个JVM内存整体的概念,下面会介绍虚拟机的内存各个区域,这个是理解JVM的第一步。


程序计数器

程序计数器是字节码解释器执行字节码的行号指示,存放当前正在执行的字节码的地址。java多线程是通过线程轮流切换来获取处理器的执行时间,任何一个时刻,一个处理器只能处理一个线程的字节码,为了在切换线程后能恢复到正确的代码位置, 所以每个线程都有自己独立的程序计数器。此内存区域是jvm中唯一没有OutOfMemeryError的区域。

虚拟机栈

经常说的堆和栈只是泛指程序猿比较关注的是这两块内存区域,实际内存区域不止堆和栈。 虚拟机栈也是线程私有的,它的生命周期和线程一样。虚拟机栈是java方法执行的内存模型,主要记录局部变量表、操作数栈、动态链接、方法出口信息等,每次方法的执行都伴随着栈帧的入栈和出栈。
局部变量表主要存放byte、short、int、char、boolean、long、float、double 这8种基本类型、对象引用。
虚拟机栈区域会报StackOverflowError和OutMemoryError错误,当请求的栈深度超过虚拟机栈的最大深度,会报StackOverflowError;若虚拟机栈自动扩容,当扩容时没有足够的内存时会报OutMemoryError错误。

本地方法栈

虚拟机栈是为调用java方法服务,本地方法栈是为调用本地native方法服务

堆(Heap)

堆是内存中最大的一块区域,用来存放数组、对象实例,是java 垃圾回收的主要对象,也称为gc堆,也是程序猿最关注的内存区域。可以通过-Xms(最小堆内存)、-Xmx(最大堆内存)来设置堆的大小。
为了提高堆内存的利用率和垃圾回收的效率,堆内存分年轻代和老年代,年轻代为Eden、From Survivor、To Survivor,一般三个代的大小比例为8:1:1,为什么要设置两个Survivor代呢?因为新创建的对象都会进入Eden代,大部分Eden代的对象都是朝生夕死的,在年轻代通过复制算法回收垃圾时,可以利用From Survivor和To Survivor来回倒腾存活的对象,提高内存利用率和垃圾回收效率。
堆内存是公用的,线程共享的,同时堆内存会报OutofMemoryError。

方法区

方法区也是公用的,线程共享的。方法区存放类的信息、类字段、类方法、常量、静态变量以及及时编译后的代码等数据。在HotSpot虚拟机中,方法区被称为永久代。

运行时常量池

运行时常量池是方法区中的一部分,主要存放在编译期生成的字面量和符号引用,比如常量;在程序运行时也可以将常量放入常量池中,比如String类的intern()方法。

注:以上是自己的个人理解,如有错误请指正!