Java面试高频知识点汇总 JVM专题
JVM,Java虚拟机,是Java实现跨平台运行的核心组件,也是面试必考的知识点,本篇博文全篇默认标记为重要。
介绍下Java内存区域(运行时数据区) / 介绍下JVM内存模型
Java虚拟机在执行Java程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK1.8和之前的版本有所不同。
JDK1.8之前:
JDK1.8之后:(即原方法区从运行时数据区移到直接内存中的元空间)。
线程私有的:
- 程序计数器
- 虚拟机栈
- 本地方法栈
线程共享的:
- 堆
- 方法区
- 直接内存(非允许时数据区的一部分)
程序计数器
程序计数器是一块较小的内存空间可以看作当前线程所执行的字节码的行号指示器。其主要功能概括为如下:
- 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如顺序执行、选择、循环、异常处理。
- 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候知道该线程上次运行到哪里。
程序计数器是唯一一个不会出现OOM
的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。
Java虚拟机栈
同程序计数器,Java虚拟机也是线程私有的,它的生命周期和线程相同,描述的是Java方法执行的内存模型,每次调用的方法都是通过栈传递的。
Java内存可以粗糙的区分为堆(Heap)内存和栈(Stack)内存,其中栈就是现在说的虚拟机栈,或者说虚拟机栈中的局部变量表。(Java虚拟机栈由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口等信息。)
Java虚拟机栈出抛出两种异常:StackOverflowError
和OutOfMemoryError
。
-
StackOverFlowError
:若Java虚拟机的内存大小不允许动态扩展,那当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就会抛出StackOverFlow
。 -
OutOfMemoryError
:若Java虚拟机的内存大小允许动态扩展,且线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。
每一次方法调用都会有一个对应的栈帧被压入虚拟机栈,每一次方法调用结束(return或者抛出异常),都会有一个栈帧被弹出。
本地方法栈
作用与虚拟机栈非常相似,区别在于:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用的Native方法服务。在HotSpot虚拟机本地方法栈和Java虚拟机栈合二为一。
本地方法在执行的时候,在本地方法栈也会创建一个栈帧。用于存放本地方法的局部变量表、操作数栈、动态链接、出口信息(同虚拟机栈)。
方法执行完毕之后相应的栈帧也会被弹出并释放空间,也会出现StackOverFlow和OutOfMemoryError两种异常。
堆
堆区是java虚拟机所管理内存中最大的一块,Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域唯一的目的就是存放对象实例,几乎所有对象实例以及数组都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage Collected Heap)。从垃圾回收的角度,由于现在收集器基本采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代:在细致一点:Eden空间、From Survivor、To Survivor空间等。进一步划分的目的是更好地回收内存或者更快地分配内存。
方法区
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代码等数据。尽管Java虚拟机规范将方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-heap,目的是与Java堆区区分开。
参考
Java Guide面试突击版,百度可得最新版本,这里可能有删减,增加和修正。
- Go语言位操作实例
- 通过Snapshot Standby来精确评估SQL性能 (r9笔记第73天)
- mongodb11天之屠龙宝刀(三)基本操作:增删改查与mysql对比
- Go语言 实现bitmap
- 最近的几个技术问题总结和答疑(八) (r9笔记第72天)
- Java基础-day05-代码题
- MySQL级联复制的同步问题(一) (r9笔记第71天)
- GO语言 TCP传输实例
- JavaScript 性能优化技巧分享
- 一个拷贝操作导致的潜在监听类问题(r9笔记第70天)
- Java基础-day05-基础题
- 【Go 语言社区算法课程 第一季 第3节 hash算法实现
- mongodb11天之屠龙宝刀(四)高级查询:MongoDB内嵌字段查询
- merge语句导致的ORA错误分析(r9笔记第67天)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 浅谈keras2 predict和fit_generator的坑
- 使用python实现名片管理系统
- PHP实现PDO操作mysql存储过程示例
- Python bisect模块原理及常见实例
- PHP的curl函数的用法总结
- Python函数的迭代器与生成器的示例代码
- PHP中检查isset()和!empty()函数的必要性
- python代码中怎么换行
- PHP让网站移动访问更加友好方法
- python代码区分大小写吗
- php面试中关于面向对象的相关问题
- python实现在线翻译
- Python字符串格式化常用手段及注意事项
- PHP count_chars()函数讲解
- 浅谈keras使用中val_acc和acc值不同步的思考