你学会了吗 JVM内存区域划分精讲
大家好,咱们又见面了。有小同伴说 JVM 内存区域在学习与面试的时刻经常理不清,为了处置这位小同伴的困扰,我将经过两篇文章为大家理清 JVM 内存区域划分,这篇是第一篇将为大家引见 JVM 内存区域的逻辑概念,将和大家唠一唠 HotSpot 虚构机成功的一些小细节。安保带系好,发车咯!
首先咱们来明白一下 运转时数据区 的概念,Java 虚构机在口头 Java 程序的环节中会将它所治理的内存划分为若干不同的数据区,这些数据区就是运转时数据区,这些区域有各自的用途和生命周期。
依据《Java 虚构机规范》的规则 JVM 所治理的内存分为:虚构机栈、本地方法栈、程序计数器、方法区和堆这五种运转时数据区。
上方咱们来区分引见他们的逻辑概念。
须要留意,逻辑概念只是《Java虚构机规范》中对运转时数据区启动的逻辑规范,不同的虚构机的详细成功会略有差异。
虚构机栈也是咱们常说的 Java 栈,是线程私有的,在每一个线程启动的时刻都会创立一个虚构机栈。
虚构机栈的生命周期和线程分歧,虚构机栈的外部存储着一个个栈帧,对应着 Java 方法的一次性次调用,方法被调用则压栈,方法调用完结则出栈。
每一个栈帧外部又存储了部分变量表、方法前往地址、操作数栈、灵活链接等信息。
在虚构机栈规范了两种异常状况。一是当线程恳求的栈深度大于虚构机所准许的深度则会抛出 SOF(StackOverflowError)异常;二是当虚构机栈容量灵活裁减时不可放开到足够的内存则会抛出 OOM(OutOfMemoryError)异常。
本地方法栈的作用与虚构机栈相似,只不过虚构机栈服务于 Java 方法调用,本地方法栈服务于本地方法(native)调用。
本地方法栈也是线程私有的,且与虚构机栈分歧,在栈深度异常和裁减失败时区分会抛出 SOF 异常和 OOM 异常。
程序计数器用作线程所口头字节码的行号批示器,雷同是线程私有的,它会存储正在口头的字节码指令地址,并在字节码指令口头完结后切换为下一步需口头的字节码指令地址,线程就在程序计数器的推进下一步步口头。
假设口头的是本地方法,则程序计数器会存储 Undefined。
方法区是各个线程共享的一块内存区域,重要用于存储已被虚构机加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码缓存等数据。
JVM 封锁前方法区将会被监禁。
方法区的常量重要被划分为运转时常量池和字符串常量池两大区域。
字节码文件中有一个区域叫做常量池表(Constant Pool Table),常量池表重要用于存储编译器生成的各种字面量与符号援用。
常量池表可以看作是一张表,虚构机指令依据这张常量表找到要口头的类名、方法名、参数类型、字面量等类型
而常量池表存储的内容将在类加载后寄存到方法区的运转时常量池中。
至于字符串常量池就是用于贮存字符串。
须要留意 Java 中的基本类型的包装类的大部分都成功了常量池技术,不过这里的常量池严厉来说应该叫做对象池,所以它们归属于堆,并不属于方法区。
无论在不同版本的虚构机成功中字符串常量池和静态变量的存储位置出现了怎样的变动,在逻辑上这两个区域是永远归属于方法区的。
方法区在内存裁减失败的时刻雷同会抛出 OOM 异常。
堆和方法区一样也是各个线程共享的一块内存区域。堆也就是咱们常说的 Java 堆,也是渣滓回收器重要治理的区域(方法区可以选用不成功渣滓搜集),“简直”一切的对象实例都在这里调配内存。
在规范中,堆可以处于在物理上不延续的内存空间,只需逻辑上延续即可,不过关于数组这种大对象,为了成功便捷和提高性能,大少数虚构机成功都会思考经常使用延续的内存空间。
在干流的虚构机成功中,堆都可以经过-Xms 和-Xmx 设置容量,假设堆中的内存无余以成功对象的实例调配,且堆不可再裁减时就会抛出 OOM 异常,这也是 OOM 异常最频发的一块区域。