轻松get JVM——Java运行时的数据区域

Java内存区域的那些事

楼房之地基,知晓内存区域,才能知晓JVM

Java的内存区域的管理是“全自动”的,每一个刚刚见识的人都会觉得神奇

Java的自动管理内存,使得我们不需要操作释放内存的代码,不容易出现内存泄漏与溢出的现象。

但是我们不得不提防,一旦出现了内存问题,知晓虚拟机的工作模式,才能排出错误。

运行时数据区域

这张图很重要,要熟记

Java虚拟机在执行Java程序时,将其所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建和销毁时间,有的区域,随着虚拟机进程的启动而存在,有的依赖用户线程的启动和结束。

1、程序计数器

程序计数器(Program Counter Register)

一块较小内存空间,是当前线程所执行的字节码行号指示器。字节码解释器工作时通过改变计数器达到语句的切换功能。

“线程私有”,各线程都拥有,互相独立,互不影响。

PC计数器是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域

tips

若为Java方法,计数器记录的是正在执行的虚拟机字节码指令的地址

若为Native方法,这个计算器值为

Native方法为Java的本地方法,Java依赖了很多本地其他语言的代码,这些代码将使用Native注册在Java虚拟机中,供Java使用

2、Java虚拟机栈

Java虚拟机栈(Java Virtual Machine Stacks)

描述Java方法执行的内存模型,每个方法在执行时都会创建一个栈帧(Stack Frame,方法运行时的基础数据结构),存放局部变量表(编译期可知的基础数据类型)、操作数栈、动态链接、方法出口等等信息

线程私有,生命周期与线程相同。

空间以Slot为单位,64位数据占两个。

两个异常:

  • StackOverflowError:线程请求深度(方法调用,算术运算会使用)大于虚拟机所允许的深度(编译时指定)。
  • OutOfMemoryError:虚拟机栈在动态扩展时,无法请求到足够的内存

3、本地方法栈

本地方法栈(Native Method Stack)

类似虚拟机栈,为虚拟机使用到的Native方法服务

两个异常:

  • StackOverflowError:线程请求深度(方法调用,算术运算会使用)大于虚拟机所允许的深度(编译时指定)。
  • OutOfMemoryError:虚拟机栈在动态扩展时,无法请求到足够的内存

4、Java堆

Java堆(Java Heap)

Java虚拟机所管理的最大块,垃圾收集器管理的主要区域,故也称“GC堆”

存放对象实例,几乎所有的对象实例都在这里分配内存

被所有线程共享

异常

  • OutOfMemoryError:堆中没有内存完成实例分配,并且堆无法再扩展

从垃圾回收的角度,Java堆可以细分为:老年代和新生代。

Java堆可能划分出多个线程私有的分配缓冲区

Java堆可能在不连续的内存空间,但是逻辑上是连续的

5、方法区

方法区(Method Area)

用于存储已被虚拟机加载的类信息常量静态常量即时编译器(JLT,将字节码直接翻译为机器代码,加速执行)编译后的代码等数据

被所有线程共享

Java虚拟机规范将其描述为堆的一个逻辑部分,但有一个别名“非堆”,被多数人称为“永久代

关于字符串常量池,在JDK1.6中,字符串在方法区拥有对象,在JDK1.7中只有引用,在jdk8中,永久代(方法区)被元空间取代了。

https://juejin.im/post/5c160420518825235a05301e

6、运行时常量池

运行时常量池(Runtime Constant Pool),方法区的一部分,

用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放

除了Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。

动态性:运行期间也能将新变量放入常量池。(如**String类的intren()**方法)

7、直接内存

直接内存(Direct Memory)

虚拟机外的内存

NIO:JDK1.4中新引入,引入一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,可以直接使用Native函数库分配堆外内存,然后通过一个存储在Java堆中DirectByteBuffer对象作为这块内存的引用进行操作。

可能的异常:OutOfMemoryError

猜你喜欢

转载自blog.csdn.net/weixin_44494373/article/details/107250982