Java 的内存模型

 2019-12-10 16:14  阅读(968)
文章分类:Java Core

Java虚拟机存在着若干个不同的数据区域,他们有的是跟随虚拟机进程的启动而存在,有的依赖用户线程的启动而存在。 Java虚拟机所管理的内存区域主要包含这些区域:

20191210001677\_1.png

图中黑色区域,为线程共享区域;白色区域,为线程私有区域

堆(Heap)

堆是程序中的对象实例被存放的区域,所以是虚拟机中管理内存最大的一块,也是GC管理的主要区域、最容易产生内存泄漏与OOM的地方。堆的生命周期与虚拟机相同(也就是说与运行在此虚拟机上的程序的生命周期相同),因此它是线程共享的,从内存分配的角度来看,Java堆会被划分成不同线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB);而从现有虚拟机GC的分代收集算法来看,它还可以被细分为:新生代和老年代,如果再细致一点的话就是Eden空间,From Survivor空间,To Survivor空间。当堆无法申请到足够的内存时,虚拟机会抛出OutOfMemoryError异常。

方法区

很容易被名字误导,虽然叫做方法区,但实际却是存储被虚拟机加载的类信息、常量、静态变量、JIT编译器编译后的代码等。它的生命周期与虚拟机相同。值得注意的是,Java虚拟机规范将方法区描述为堆的一个逻辑部分,但通常我们将它与堆区分开来(在HotSpot虚拟机中,方法区对应着永久代(Permanent Generation))。当方法区无法申请到足够的内存时,虚拟机会抛出OutOfMemoryError异常。

虚拟机栈

虚拟机栈是Java虚拟机中用来描述方法运行的内存模型,它在每个方法运行时都会创建一个帧栈,包含局部变量表、操作数栈、动态链接、方法出口等信息。由于存储的是方法执行过程中的信息,它当然是线程私有的,生命周期与线程相同。在递归深度大于虚拟机所允许的最大深度时,它会抛出StackOverflowError的异常;但如果虚拟机栈支持动态扩展的话,虚拟机会尝试扩展到不能申请到足够的内存为止。如果申请不到足够的内存了,他就会抛出OutOfMemoryError异常。

本地方法栈

本地方法栈与虚拟机栈类似,都是用来描述方法运行的内存模型,唯一的不同是,本地方法栈是用来管理Native方法的。在HotSpot虚拟机中,他们甚至是合在一起的;因此,与虚拟机栈类似,本地方法栈也会抛出StackOverflowError或OutOfMemoryError异常。

程序计数器

程序计数器记录着当前程序所执行到的字节码的行号(这不同于Java代码中的行号), 有点类似于汇编中的ES:IP。所不同的是,后者指示着程序当前执行的代码段的指令地址。循环、分支、跳转、异常处理、线程恢复等,都依赖于它来完成。由于多线程时每个线程都需要一个程序计数器来指示当前执行到的行数,所以它是线程私有的。同时,程序计数器也是Java虚拟机规范中唯一一个没有OutOfMemoryError异常抛出的区域。

总结

内存区域 所存储信息 异常
内存区域 所存储信息 异常
堆(Heap) 对象存放区域 OutOfMemoryError
方法区 类信息、常量、静态变量等 OutOfMemoryError
虚拟机栈 操作数栈、局部变量表、动态链接、方法出口等 OutOfMemoryError、StackOverflowError
本地方法栈 Native方法 OutOfMemoryError、StackOverflowError
程序计数器 执行到的字节码行号



点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java 的内存模型

相关推荐