万万没想到,JVM内存结构的面试题能够问的这么难?

在个人博客中,以前有不少文章介绍过JVM内存结构,相信不少看多我文章的朋友对这部分知识都有必定的了解了。算法

那么,请你们尝试着回答一下如下问题:数组

一、JVM管理的内存结构是怎样的?
二、不一样的虚拟机在实现运行时内存的时候有什么区别?
三、运行时数据区中哪些区域是线程共享的?哪些是独享的?
四、除了JVM运行时内存之外,还有什么区域能够用吗?
五、堆和栈的区别是什么?
六、Java中的数组是存储在堆上仍是栈上的?
七、Java中的对象建立有多少种方式?
八、Java中对象建立的过程是怎么样的?
九、Java中的对象必定在堆上分配内存吗?
十、如何获取堆和栈的dump文件?服务器

以上10道题,若是您能够所有准确无误的回答的话,那说明你真的很了解JVM的内存结构以及内存分配相关的知识了,若是有哪些知识点是不了解的,那么本文正好能够帮你答疑解惑。函数

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

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

spa

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

各个区域有各自不一样的做用,关于各个区域的做用就不在本文中相信介绍了。code

可是,须要注意的是,上面的区域划分只是逻辑区域,对于有些区域的限制是比较松的,因此不一样的虚拟机厂商在实现上,甚至是同一款虚拟机的不一样版本也是不尽相同的。对象

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

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

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

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

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

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

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

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

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

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

除了JVM运行时内存之外,还有什么区域能够用吗?

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

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

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

堆和栈的区别是什么?

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

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

Java中的数组是存储在堆上仍是栈上的?

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

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

Java中的对象建立有多少种方式?

Java中有不少方式能够建立一个对象,最简单的方式就是使用new关键字。

User user = new User();

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

User user = User.class.newInstance();

或者使用Constructor类的newInstance:

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

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

Java中对象建立的过程是怎么样的?

对于一个普通的Java对象的建立,大体过程以下:

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

Java中的对象必定在堆上分配内存吗?

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

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

若是JIT通过逃逸分析,发现有些对象没有逃逸出方法,那么有可能堆内存分配会被优化成栈内存分配。

十、如何获取堆和栈的dump文件?

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

可使用在服务器上使用jmap命令来获取堆dump,使用jstack命令来获取线程的调用栈dump。

图片描述

相关文章
相关标签/搜索