作者:道士也调情 | 来源:互联网 | 2023-08-28 14:35
在上一篇文章中我们聊了下JVM类加载机制相关的内容,现在来简单回顾一下。
关于类加载机制,有几点大家需要搞明白:
JVM内存区域
了解完JVM的类加载机制之后,还要了解一下JVM的内存区域是怎么划分的,这也是互联网公司面试必问的点。
那到底JVM的内存区域是怎么划分的呢?
JVM内存区域主要包含:方法区 程序计数器 Java虚拟机栈 本地方法栈 Java堆,如下图:
1、方法区:
方法区在JDK1.8之后把名字改成了“Metaspace",可以翻译成"元数据空间",这是一块线程共享的内存空间,主要用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
Java虚拟机规范将方法区描述为堆的一个逻辑部分,但它有一个别名”Non-Heap 非堆“ 用于与Java堆区分。
很多人愿意把方法区成为”永久代“,本质上两者并不等价。HotSpot虚拟机 团队选择把GC分代收集扩展至方法区,或者说使用永久带实现方法区而已。
方法区存在的问题:
运行时常量池也是方法区的一个部分,主要用于存放编译器生成的各种字面量和符号引用。类加载后会进入方法区的运行时常量池
运行时常量池存在的问题:
2、虚拟机栈
虚拟机栈是线程私有的内存空间,其生命周期与线程相同,是用于Java方法执行的内存模型。方法执行时会创建栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等。
虚拟机栈存在的问题:
3、本地方法栈
其发挥的作用和存在的问题与Java虚拟机栈类似,这里主要说一下其区别。其区别主要是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机使用到Native方法服务。
知识点:Hotspot虚拟机中将本地方法栈与虚拟机栈合二为一。
4、Java堆
Java堆是虚拟机中占内存最大的一块内存空间,是所有线程共享的内存区域,当虚拟机启动的时候就会创建。它的作用主要是存放对象实例,几乎所有的对象实例都在这里分配内存。我们来看下Java虚拟机规范是怎么描述它的:
所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配到堆上也渐渐变得不是那么”绝对“了。
这一块内存空间也是垃圾收集器管理的主要区域,所以有时候也被称为”GC堆“。
Java堆存在的问题:
5、程序计数器
程序计数器是线程私有的一块占用较小的内存空间,主要用于记录当前线程执行到哪里了。而且这也是唯一一个没有内存溢出的区域。
6、直接内存
除了以上几块内存空间外,还有一块内存空间就是直接内存,它不属于运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分频繁使用也可能导致OutOfMemoryError异常。NIO可以使用Native函数库直接分配堆外内存空间。
文末小结
关于jvm内存区域空间要重点关注方法区,程序计数器,Java虚拟机栈和Java堆这些内存区域的作用。只有在了解了虚拟机是怎么使用内存的之后,才能在出现内存溢出和泄漏时更快速的定位和排查解决问题。
最后附上一张关于Java内存区域的思维导图