【第二章:Java核心技术解析】第11节:Java进阶 - JVM内存机制(上)


大家好,很高兴我们可以继续学习交流Java高频面试题。从本小节开始,我们将用三个小节来交流学习JVM内存机制相关的技术原理。

JVM内存机制是Java面试中的重中之重,面试中的绝对热点。作为一名优秀的Java开发工程师,日常工作中必不可少的要与JVM打交道,我们必须考虑到如何对JVM进行内存分配,应该对当前服务采用哪种垃圾回收器的问题。当我们遇到OOM内存溢出的故障时,也必须去分析研究其原因,所以还需要使用到各个内存调优分析手段。

作为Java面试中的重点,我希望大家可以扎实理解掌握JVM相关的技术原理。本小节所涉及的知识点包括JVM内存的分配与回收策略以及垃圾回收的基本概念等。好了,话不多说,让我们一起来学习吧~

(1)JVM中的内存是怎么划分的?(重点掌握)

答:JVM中的内存主要划分为5个区域,即方法区,堆内存,程序计数器,虚拟机栈以及本地方法栈。下边是Java虚拟机运行时数据区示意图:

图片说明

方法区:方法区是一个线程之间共享的区域。常量,静态变量以及JIT编译后的代码都在方法区。主要用于存储已被虚拟机加载的类信息,也可以称为“永久代”,垃圾回收效果一般,通过-XX:MaxPermSize控制上限。

堆内存:堆内存是垃圾回收的主要场所,也是线程之间共享的区域,主要用来存储创建的对象实例,通过-Xmx 和-Xms 可以控制大小。

虚拟机栈(栈内存):栈内存中主要保存局部变量、基本数据类型变量以及堆内存中某个对象的引用变量。每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表,操作数栈,动态链接,方法出口等信息。栈中的栈帧随着方法的进入和退出有条不紊的执行着出栈和入栈的操作。

程序计数器: 程序计数器是当前线程执行的字节码的位置指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,是内存区域中唯一一个在虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

本地方法栈: 主要是为JVM提供使用native 方法的服务。

解析:

JVM的内存划分主要由以上五个区域组成,我们需要重点掌握堆内存,栈内存以及方法区域的定义和作用,做到准确理解与阐述。


(2)可以说一下对象创建过程中的内存分配吗?

答:一般情况下我们通过new指令来创建对象,当虚拟机遇到一条new指令的时候,会去检查这个指令的参数是否能在常量池中定位到某个类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析和初始化。如果没有,那么会执行类加载过程。

通过执行类的加载,验证,准备,解析,初始化步骤,完成了类的加载,这个时候会为该对象进行内存分配,也就是把一块确定大小的内存从Java堆中划分出来,在分配的内存上完成对象的创建工作。

对象的内存分配有两种方式,即指针碰撞和空闲列表方式。

指针碰撞方式:

假设Java堆中的内存是绝对规整的,用过的内存在一边,未使用的内存在另一边,中间有一个指示指针,那么所有的内存分配就是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。

空闲列表方式:

如果Java堆内存中不是规整的,已使用和未使用的内存相互交错,那么虚拟机就必须维护一个列表用来记录哪块内存是可用的,在分配的时候找到一块足够大的空间分配对象实例,并且需要更新列表上的记录。

需要注意的是,Java 堆内存是否规整是由所使用的垃圾收集器是否拥有压缩整理功能来决定的,关于垃圾收集器我们在下一小节重点介绍。

看到这里,聪明的你肯定想到了内存分配是否也应该考虑线程安全的问题呢?

那么内存的分配如何保证线程安全呢?

  • 对分配内存空间的动作进行同步处理,通过“CAS + 失败重试”的方式保证更新指针操作的原子性
  • 把分配内存的动作按照线程划分在不同的空间之中,即给每一个线程都预先分配一小段的内存,称为本地线程分配缓存(TLAB),只有TLAB用完并分配新的TLAB时,才需要进行同步锁定。 虚拟机是否使用TLAB,可以通过-XX: +/-UserTLAB参数来设定

(3)对象被访问的时候是怎么被找到的?

答:通过对栈内存和堆内存的介绍,我们知道了当创建一个对象的时候,在栈内存中会有一个引用变量,指向堆内存中的某个具体的对象实例。

Java虚拟机规范中并没有规定这个引用变量应该以何种方式去定位和访问堆内存中的具体对象。目前常见的对象访问方式有两种,即句柄访问方式和直接指针访问方式,分别介绍如下。

句柄访问方式:

在JVM的堆内存

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java开发岗高频面试题全解析 文章被收录于专栏

<p> Java开发岗高频面试题全解析,专刊正文共计31节,已经全部更新完毕。专刊分9个模块来对Java岗位面试中的知识点进行解析,包括通用面试技能,Java基础,Java进阶,网络协议,常见框架以及算法,设计模式等。专刊串点成面的解析每个面试题背后的技术原理,由浅入深,循序渐进,力争让大家掌握面试题目的背后的技术原理,摒弃背题模式的陋习。 专刊详细信息,请查阅专刊大纲和开篇词的介绍。 本专刊购买后即可解锁所有章节,故不可以退换哦~ </p> <p> <br /> </p>

全部评论
之前看过jvm,这么一整理感觉整个知识体系好清晰,赞
2 回复 分享
发布于 2021-02-04 11:16
感觉楼主的版本意识不够,概念描述有的有点含糊。
1 回复 分享
发布于 2020-10-29 15:32
Jul 13打卡
1 回复 分享
发布于 2020-07-14 11:08
打卡
1 回复 分享
发布于 2020-01-02 23:23
感觉消化的不太好,楼主这块还有更新吗
1 回复 分享
发布于 2020-01-02 16:26
我又回来了,准备秋招
点赞 回复 分享
发布于 2022-08-03 20:00
不知道多少刷了,目前拿了一个offer
点赞 回复 分享
发布于 2022-05-06 10:03
full gc应该是对新生代,老年代,永久代一起回收,而不是只针对老年代吧。major gc是发生在年轻代和老年代的
点赞 回复 分享
发布于 2022-03-15 20:47
16# 是你抄的JAVA GUIDE还是JAVA GUIDE抄的你?
1 回复 分享
发布于 2021-03-02 03:40
打卡
点赞 回复 分享
发布于 2020-11-19 18:35
为什么要设置年轻代和老年代的比例为8:1呢?这样设计的目的是啥呢
点赞 回复 分享
发布于 2020-09-12 18:17
打卡 一刷。
点赞 回复 分享
发布于 2020-09-10 11:04
二刷打卡
点赞 回复 分享
发布于 2020-08-20 14:11
楼主你好, 发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小。这句话好难理解啊,之前晋升的若小于老年代的剩余空间大小那还怎么晋升呢?
点赞 回复 分享
发布于 2020-05-23 09:21
这一页真是太难理解了,特别是对象创建过程中的内存分配这个问题。建议大家配合b站和博客上的一些视频进行学习,搜索创建对象内存分析就有很多很清楚的表达。
点赞 回复 分享
发布于 2020-04-29 16:57
堆内存上的分配与回收,第一个参数应该是-XX:PretenureSizeThreshold
点赞 回复 分享
发布于 2020-02-26 16:47
有一个问题想请教一下,上文说Full GC是发生在老年代的GC,那Major GC呢?我的理解是Full GC是全体范围的GC,Major GC是只发生在老年代的GC.求解答
点赞 回复 分享
发布于 2020-02-20 10:58
打卡....在内存分配图里没有画survivor区吧...在堆内存大小设置的时候,应该是虚拟机设置不是服务器设置吧...
点赞 回复 分享
发布于 2020-01-18 17:28
希望栏主多添加点图,有的知识点图示比语言更直观简练
点赞 回复 分享
发布于 2019-12-06 15:27

相关推荐

评论
6
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务