△Hollis, 一个对Coding有着独特追求的人△

这是Hollis的第 223 篇原创分享

作者 l Hollis

来源 l Hollis(ID:hollischuang)

在我的博客中,之前有很多文章介绍过JVM内存结构,相信很多看多我文章的朋友对这部分知识都有一定的了解了。

那么,请大家尝试着回答一下以下问题:

1、JVM管理的内存结构是怎样的? 2、不同的虚拟机在实现运行时内存的时候有什么区别? 3、运行时数据区中哪些区域是线程共享的?哪些是独享的? 4、除了JVM运行时内存以外,还有什么区域可以用吗? 5、堆和栈的区别是什么? 6、Java中的数组是存储在堆上还是栈上的? 7、Java中的对象创建有多少种方式? 8、Java中对象创建的过程是怎么样的? 9、Java中的对象一定在堆上分配内存吗? 10、如何获取堆和栈的dump文件?以上10道题,如果您可以全部准确无误的回答的话,那说明你真的很了解JVM的内存结构以及内存分配相关的知识了,如果有哪些知识点是不了解的,那么本文正好可以帮你答疑解惑。

Q1:JVM管理的内存结构是怎样的?

Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。《Java虚拟机规范》中规定了JVM所管理的内存需要包括一下几个运行时区域:


Java虚拟机运行时数据区域主要包含了PC寄存器(程序计数器)、Java虚拟机栈、本地方法栈、Java堆、方法区以及运行时常量池。

各个区域有各自不同的作用,关于各个区域的作用就不在本文中相信介绍了。

但是,需要注意的是,上面的区域划分只是逻辑区域,规范对于有些区域的限制是比较松的,所以不同的虚拟机厂商在实现上,甚至是同一款虚拟机的不同版本也是不尽相同的。

Q2:不同的虚拟机在实现运行时内存的时候有什么区别?

前面提到过《Java虚拟机规范》定义的JVM运行时所需的内存区域,不同的虚拟机实现上有所不同,而在这么多区域中,规范对于方法区的管理是最宽松的,规范中关于这部分的描述如下:

方法区在虚拟机启动的时候创建,虽然方法区是堆的逻辑组成部分,但是简单的虚拟机实现可以选择在这个区域不实现垃圾收集与压缩。本版本的规范也不限定实现方法区的内存位置和代码编译的管理策略。方法区的容量可以是固定的,也可以随着程序执行的需求动态扩展,并在不需要过多的空间时自行收缩。方法区在实际内存空间站可以是不连续的。

这一规定,可以说是给了虚拟机厂商很大的自由。

虚拟机规范对方法区实现的位置并没有明确要求,在最著名的HotSopt虚拟机实现中(在Java 8 之前),方法区仅是逻辑上的独立区域,在物理上并没有独立于堆而存在,而是位于永久代中。所以,这时候方法区也是可以被垃圾回收的。

实践证明,JVM中存在着大量的声明短暂的对象,还有一些生命周期比较长的对象。为了对他们采用不同的收集策略,采用了分代收集算法,所以HotSpot虚拟机把的根据对象的年龄不同,把堆分位新生代、老年代和永久代。

在Java 8中 ,HotSpot虚拟机移除了永久代,使用本地内存来存储类元数据信息并称之为:元空间(Metaspace)


Q3:运行时数据区中哪些区域是线程共享的?哪些是独享的?

在JVM运行时内存区域中,PC寄存器、虚拟机栈和本地方法栈是线程独享的。

而Java堆、方法区是线程共享的。但是值得注意的是,Java堆其实还未每一个线程单独分配了一块TLAB空间,这部分空间在分配时是线程独享的,在使用时是线程共享的。(TLAB介绍)

Q4:除了JVM运行时内存以外,还有什么区域可以用吗?

除了我们前面介绍的虚拟机运行时数据区以外,还有一部分内存也被频繁使用,他不是运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,他就是——直接内存。

直接内存的分配不受Java堆大小的限制,但是他还是会收到服务器总内存的影响。

在JDK 1.4中引入的NIO中,引入了一种基于Channel和Buffer的I/O方式,他可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的应用进行操作。


Q5:堆和栈的区别是什么?

堆和栈(虚拟机栈)是完全不同的两块内存区域,一个是线程独享的,一个是线程共享的,二者之间最大的区别就是存储的内容不同:

堆中主要存放对象实例。 
栈(局部变量表)中主要存放各种基本数据类型、对象的引用。

Q6:Java中的数组是存储在堆上还是栈上的?

在Java中,数组同样是一个对象,所以对象在内存中如何存放同样适用于数组;

所以,数组的实例是保存在堆中,而数组的引用是保存在栈上的。


Q7:Java中的对象创建有多少种方式?

Java中共有5种方式可以创建一个对象。

最简单的方式就是使用new关键字。

User user = new User();

除此以外,还可以使用反射机制创建对象:

User user = User.class.newInstance();

或者使用Constructor类的newInstance:

Constructor<User> constructor = User.class.getConstructor();User user = constructor.newInstance(););User user = constructor.newInstance();

除此之外还可以使用clone方法和反序列化的方式,这两种方式不常用并且代码比较复杂,就不在这里展示了,感兴趣的可以自行了解下。

Q8:Java中对象创建的过程是怎么样的?

对于一个普通的Java对象的创建,大致过程如下:

1、虚拟机遇到new指令,到常量池定位到这个类的符号引用。 
2、检查符号引用代表的类是否被加载、解析、初始化过。 
3、虚拟机为对象分配内存。 
4、虚拟机将分配到的内存空间都初始化为零值。 
5、虚拟机对对象进行必要的设置。 
6、执行方法,成员变量进行初始化。

Q9:Java中的对象一定在堆上分配内存吗?

前面我们说过,Java堆中主要保存了对象实例,但是,随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。

其实,在编译期间,JIT会对代码做很多优化。其中有一部分优化的目的就是减少内存堆分配压力,其中一种重要的技术叫做逃逸分析。

如果JIT经过逃逸分析,发现有些对象没有逃逸出方法,那么有可能堆内存分配会被优化成栈内存分配。(关于逃逸分析和栈上分配可以参考:深入理解Java中的逃逸分析、对象并不一定都是在堆上分配内存的)


Q10:怎么如何获取堆和栈的dump文件?

Java Dump,Java虚拟机的运行时快照。将Java虚拟机运行时的状态和信息保存到文件。

可以使用在服务器上使用jmap命令来获取堆dump,使用jstack命令来获取线程的调用栈dump。(关于jmap和jstack可以参考:Java命令学习系列(三)——Jmap、Java命令学习系列(二)——Jstack)

以上,就是本文的全部内容,对于其中的很多知识点,作者并未逐一展开,感兴趣的朋友可以自行学习一下,关于Java虚拟机相关知识,推荐三本书:《深入理解Java虚拟机》、《HotSpot实战》以及《Java虚拟机规范(第8版)》,本文中内容也参考了这三本书中很多内容。希望对你有帮助。

Java工程师成神之路系列文章

在 GitHub 更新中,欢迎关注,欢迎star。

直面Java第262期:volatile是如何解决有序性问题的?

深入并发第009期:到底什么是Java内存模型?

- MORE | 更多精彩文章 -

  • 推荐几个来自BATJ等一线互联网公司的大神的公众号!

  • Apache的架构师们遵循的30条设计原则

  • 一个员工的离职成本到底有多恐怖!

  • 2019年美团,滴滴,蘑菇街Java大数据面经分享!

如果你喜欢本文,

请长按二维码,关注 Hollis.

转发至朋友圈,是对我最大的支持。

好文章,我在看❤️

原创 | 万万没想到,JVM内存结构的面试题可以问的这么难?相关推荐

  1. 万万没想到,JVM内存结构的面试题可以问的这么难?

    在我的博客中,之前有很多文章介绍过JVM内存结构,相信很多看多我文章的朋友对这部分知识都有一定的了解了. 那么,请大家尝试着回答一下以下问题: 1.JVM管理的内存结构是怎样的?  2.不同的虚拟机在 ...

  2. jvm内存结构_聊聊JVM内存结构

    起因 我们经常会在面试的时候被问到JVM的内存结构,很多人会觉得这东西真的有用吗?也就是面试造火箭,入职拧螺丝.问这个就是纯粹来刁难人的吧. 但实际上,我们细想一下. •假设你不知道局部变量实际上属于 ...

  3. 显卡暴涨,这我万万没想到啊

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 梦晨 晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI ...

  4. 科学家们竟用乐高观察细胞,网友:万万没想到啊

    杨净 子豪 发自 凹非寺 量子位 报道 | 公众号 QbitAI 玩乐高还能玩出个显微镜?! 原本以为是一个普普通通的玩具. 没想到,还真能当成显微镜来用,是能看到细胞的那种. 真·高端新玩法! 比如 ...

  5. 显卡暴涨,等等党输了,这我万万没想到啊

    梦晨 晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI 万万没想到,去年信心满满准备好钱包要买30系显卡的我,现在连1660Ti都快买不起了. 不仅官方原价3899的RTX 3070,一路 ...

  6. 2015年第21本:万万没想到,用理工科思维理解世界

    <万万没想到:用理工科思维理解世界>这本书好像是从amazon排行榜中发现的,先是下载了电子版,竟然是一个博客(学而时嘻之)的大合集,可能是网上的某人用作者的博客制作而成的,共有123章! ...

  7. Java 内存模型和 JVM 内存结构真不是一回事

    这两个概念估计有不少人会混淆,它们都可以说是 JVM 规范的一部分,但真不是一回事!它们描述和解决的是不同问题,简单来说, Java 内存模型,描述的是多线程允许的行为 JVM 内存结构,描述的是线程 ...

  8. 万万没想到,我的炼丹炉玩坏了

    一只小狐狸带你解锁NLP/ML/DL秘籍 作者:夕小瑶 前记 众所周知,夕小瑶是个做NLP的小可爱. 虽然懂点DL框架层知识,懂点CUDA和底层,但是我是做算法的哎,平时debug很少会遇到深度学习框 ...

  9. JVM内存结构和垃圾回收机制

    目录 JVM内存结构 JVM内存分配机制 对象回收判断机制 引用计数法 可达性分析算法 垃圾回收算法 标记-复制 标记-清除 标记-整理 垃圾回收器 serial(-XX:+UseSerialGC - ...

最新文章

  1. envoy实现_网络通信与治理,谁更在行?Envoy 和 Nginx 对比 | 本月送书活动来啦
  2. [react native] navigator过渡卡顿问题
  3. document.getElementById()和document.forms[0].submit()
  4. 各种排序实现以及稳定性分析
  5. 智能合约语言 Solidity 教程系列8 - Solidity API
  6. shell 获取命令执行结果_java高并发系列 第31天:获取线程执行结果,这6种方法你都知道?...
  7. 关于c#:Filter Serilog日志取决于上下文源到不同的接收器?
  8. 电脑机器人_【头条】厚积薄发!卡达电脑智能机器人之纸箱码垛机赋能智能工厂...
  9. 《梦断代码》随笔第2篇
  10. tomcat虚拟子目录设置
  11. 机器学习作业班_python神经网络搭建
  12. Awaken for Mac闹钟定时器
  13. Navicat for MySQL_11.2.15破解版
  14. 200多个引流推广渠道及技巧,全网引流布局
  15. 省市区三级联动 mysql_省市区三级联动实现
  16. 模糊控制器原理笔记(附简单demo以及MATLAB相关操作)
  17. exe文件打开方式(恢复EXE文件关联)
  18. 练习-Java循环综合练习一之住房贷款还款计算
  19. 批量抓取微信朋友圈 Java_微信朋友圈转疯了(golang写小爬虫抓取朋友圈文章)...
  20. python实验总结心得体会_山东省实验学子在“2020未来太空学者大会中国区终选赛”中获佳绩...

热门文章

  1. linux执行命令提示缺少so,Linux软件缺少动态链接库.so怎么办
  2. xp系统的WINS服务器设置,WindowsXP系统设置
  3. updatebyprimarykeyselective怎么更新某个字段为null_一千个不用 Null 的理由
  4. python爬虫第二课:url解析
  5. canopy算法流程_Canopy聚类算法(经典,看图就明白)
  6. sql空字符串判断函数_Excel数据还可这样来查询:用SQL查询输出工作表指定区域更高效!...
  7. 3-1:HTTP协议之应用层协议了解
  8. IO流练习题 实现图片的加密解密操作
  9. 1052. 爱生气的书店老板
  10. 活动安排--贪心算法C语言实现