JVM内存模型【翻译】

当你运行一个Java程序的时候,需要开辟一定的空间存放代码执行所需要的数据,
通常称之为JVM内存。
虽然如果你只是单纯的写程序,了解JVM内存的细节没有太大的必要,
但随着你越深入的了解Java的内在机制,比如做一些性能优化的时候,
你会越来越发现了解JVM内存的重要性。
当你对JVM内存有了足够的了解的时候,
你在应付内存管理,性能优化时就能更加从容自若,
作为一个程序员所必要有的好奇心来说,
理解JVM是如何分配内存,以及垃圾回收器(GC)是如何工作的本身也是一个愉快的过程。

JVM内存模型

执行一个程序的过程中,JVM会将JVM内存分成几个部分。
有些内存块会随着JVM的启动而被分配并随着JVM的退出而消亡,
有些则是线程级的数据块。
也就是说随着线程的生命周期共存。

下面是一个基本的JVM内存结构。

JVM内存模型【翻译】_第1张图片
JVM内存模型

下面简单的说一下这几个部分吧。

堆区

堆区随着JVM的启动而被分配,主要负责存储生成的class实例和数组。

堆的大小可以是固定的,或者是动态调整的(基于系统配置),
并且分配到堆上的数据并不需要是连续的。

JVM允许开发者或者用户配置堆区的初始化大小,堆是否允许动态的伸缩,以及堆的最大最小值等等。

如果需要分配内存但是堆已经占满的情况下,会抛出一个OurOfMeoryError。

方法区和运行时常量池

方法区主要用来存放每个class的结构,
例如:运行时常量,字段和方法,方法和构造函数的代码等。

方法区也是在JVM启动时被创建。
尽管从逻辑上来说它是堆区的一部分但是不能被GC给回收,
相反对于堆的垃圾回收却是强制的。
方法区可以是一个固定的大小,也可以根据需要扩张或者压缩。
方法区上的内存分配同样不必是连续的。

当JVM无法为方法区分配更多的内存时,会抛出OutOfMemoryError

JVM栈

对于每一个线程都有一个私有的栈。
堆存储帧。
栈帧用来存储数据,临时结果,动态链接,返回函数值,抛出异常等。

栈维护了局部变量,临时结果并且在函数执行和返回上起到作用。
除了将栈帧压入和压出之外,我们不会直接操作栈本身。
栈帧也是在堆上被分配的(HotSpot VM)。
同样栈上的内存分配也不需要是连续的。

正是因为这样的规定允许了栈可以是固定或者动态调整的。
如果我们使用固定大小的栈,那么对于每一个栈在初始化时所分配的大小都是不一样的。

如果栈上的内存不够分配的时候,JVM会抛出一个StackOverflowError

如果JVM栈可以动态扩展,但是当栈在初始化或者在动态扩展时所需的内存不够时,
JVM会抛出一个OutOfMemoryError

本地方法栈

本地方法栈又叫做C栈。
它支持了本地方法(通常由其他语言写成)在执行时每个线程上的内存分配。

基本上逻辑和JVM栈相似。

PC寄存器(程序计数器)

每一个JVM线程都有其独立的程序计数器。
任何时候,每个JVM线程都在执行某个单独的方法,通常叫做当前方法。

因为Java程序也包含本地代码(例如本地库),因此我们需要两种不同的方式来处理程序计数器。
当方法不是本地方法时,程序计数器将包含当前执行的JVM指令的地址,
否则标记为undefined。

这些就是关于JVM内存模型的一个简单介绍。

A 参考

https://howtodoinjava.com/java/garbage-collection/jvm-memory-model-structure-and-components/
https://docs.oracle.com/cd/B28359_01/server.111/b31107/asmcon.htm#OSTMG036

你可能感兴趣的:(JVM内存模型【翻译】)