learn.lianglianglee.com/文章/JVM 面试的 30 个知识点.md.html
2022-05-11 19:04:14 +08:00

733 lines
49 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>JVM 面试的 30 个知识点.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/文章/AQS 万字图文全面解析.md.html">AQS 万字图文全面解析.md.html</a>
</li>
<li>
<a href="/文章/Docker 镜像构建原理及源码分析.md.html">Docker 镜像构建原理及源码分析.md.html</a>
</li>
<li>
<a href="/文章/ElasticSearch 小白从入门到精通.md.html">ElasticSearch 小白从入门到精通.md.html</a>
</li>
<li>
<a href="/文章/JVM CPU Profiler技术原理及源码深度解析.md.html">JVM CPU Profiler技术原理及源码深度解析.md.html</a>
</li>
<li>
<a href="/文章/JVM 垃圾收集器.md.html">JVM 垃圾收集器.md.html</a>
</li>
<li>
<a class="current-tab" href="/文章/JVM 面试的 30 个知识点.md.html">JVM 面试的 30 个知识点.md.html</a>
</li>
<li>
<a href="/文章/Java IO 体系、线程模型大总结.md.html">Java IO 体系、线程模型大总结.md.html</a>
</li>
<li>
<a href="/文章/Java NIO浅析.md.html">Java NIO浅析.md.html</a>
</li>
<li>
<a href="/文章/Java 面试题集锦(网络篇).md.html">Java 面试题集锦(网络篇).md.html</a>
</li>
<li>
<a href="/文章/Java-直接内存 DirectMemory 详解.md.html">Java-直接内存 DirectMemory 详解.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中的SPI.md.html">Java中的SPI.md.html</a>
</li>
<li>
<a href="/文章/Java中的ThreadLocal.md.html">Java中的ThreadLocal.md.html</a>
</li>
<li>
<a href="/文章/Java线程池实现原理及其在美团业务中的实践.md.html">Java线程池实现原理及其在美团业务中的实践.md.html</a>
</li>
<li>
<a href="/文章/Java魔法类Unsafe应用解析.md.html">Java魔法类Unsafe应用解析.md.html</a>
</li>
<li>
<a href="/文章/Kafka 源码阅读笔记.md.html">Kafka 源码阅读笔记.md.html</a>
</li>
<li>
<a href="/文章/Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html">Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB Buffer Pool.md.html">MySQL · 引擎特性 · InnoDB Buffer Pool.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB IO子系统.md.html">MySQL · 引擎特性 · InnoDB IO子系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 事务系统.md.html">MySQL · 引擎特性 · InnoDB 事务系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 同步机制.md.html">MySQL · 引擎特性 · InnoDB 同步机制.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 数据页解析.md.html">MySQL · 引擎特性 · InnoDB 数据页解析.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB崩溃恢复.md.html">MySQL · 引擎特性 · InnoDB崩溃恢复.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · 临时表那些事儿.md.html">MySQL · 引擎特性 · 临时表那些事儿.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 半同步复制.md.html">MySQL 主从复制 半同步复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 基于GTID复制.md.html">MySQL 主从复制 基于GTID复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制.md.html">MySQL 主从复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 事务日志(redo log和undo log).md.html">MySQL 事务日志(redo log和undo log).md.html</a>
</li>
<li>
<a href="/文章/MySQL 亿级别数据迁移实战代码分享.md.html">MySQL 亿级别数据迁移实战代码分享.md.html</a>
</li>
<li>
<a href="/文章/MySQL 从一条数据说起-InnoDB行存储数据结构.md.html">MySQL 从一条数据说起-InnoDB行存储数据结构.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:事务和锁的面纱.md.html">MySQL 地基基础:事务和锁的面纱.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据字典.md.html">MySQL 地基基础:数据字典.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据库字符集.md.html">MySQL 地基基础:数据库字符集.md.html</a>
</li>
<li>
<a href="/文章/MySQL 性能优化:碎片整理.md.html">MySQL 性能优化:碎片整理.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html">MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:如何在日志中轻松定位大事务.md.html">MySQL 故障诊断:如何在日志中轻松定位大事务.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:教你快速定位加锁的 SQL.md.html">MySQL 故障诊断:教你快速定位加锁的 SQL.md.html</a>
</li>
<li>
<a href="/文章/MySQL 日志详解.md.html">MySQL 日志详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL 的半同步是什么?.md.html">MySQL 的半同步是什么?.md.html</a>
</li>
<li>
<a href="/文章/MySQL中的事务和MVCC.md.html">MySQL中的事务和MVCC.md.html</a>
</li>
<li>
<a href="/文章/MySQL事务_事务隔离级别详解.md.html">MySQL事务_事务隔离级别详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL优化优化 select count().md.html">MySQL优化优化 select count().md.html</a>
</li>
<li>
<a href="/文章/MySQL共享锁、排他锁、悲观锁、乐观锁.md.html">MySQL共享锁、排他锁、悲观锁、乐观锁.md.html</a>
</li>
<li>
<a href="/文章/MySQL的MVCC多版本并发控制.md.html">MySQL的MVCC多版本并发控制.md.html</a>
</li>
<li>
<a href="/文章/QingStor 对象存储架构设计及最佳实践.md.html">QingStor 对象存储架构设计及最佳实践.md.html</a>
</li>
<li>
<a href="/文章/RocketMQ 面试题集锦.md.html">RocketMQ 面试题集锦.md.html</a>
</li>
<li>
<a href="/文章/SnowFlake 雪花算法生成分布式 ID.md.html">SnowFlake 雪花算法生成分布式 ID.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html">Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 教程:如何开发一个 starter.md.html">Spring Boot 教程:如何开发一个 starter.md.html</a>
</li>
<li>
<a href="/文章/Spring MVC 原理.md.html">Spring MVC 原理.md.html</a>
</li>
<li>
<a href="/文章/Spring MyBatis和Spring整合的奥秘.md.html">Spring MyBatis和Spring整合的奥秘.md.html</a>
</li>
<li>
<a href="/文章/Spring 帮助你更好的理解Spring循环依赖.md.html">Spring 帮助你更好的理解Spring循环依赖.md.html</a>
</li>
<li>
<a href="/文章/Spring 循环依赖及解决方式.md.html">Spring 循环依赖及解决方式.md.html</a>
</li>
<li>
<a href="/文章/Spring中眼花缭乱的BeanDefinition.md.html">Spring中眼花缭乱的BeanDefinition.md.html</a>
</li>
<li>
<a href="/文章/Vert.x 基础入门.md.html">Vert.x 基础入门.md.html</a>
</li>
<li>
<a href="/文章/eBay 的 Elasticsearch 性能调优实践.md.html">eBay 的 Elasticsearch 性能调优实践.md.html</a>
</li>
<li>
<a href="/文章/不可不说的Java“锁”事.md.html">不可不说的Java“锁”事.md.html</a>
</li>
<li>
<a href="/文章/互联网并发限流实战.md.html">互联网并发限流实战.md.html</a>
</li>
<li>
<a href="/文章/从ReentrantLock的实现看AQS的原理及应用.md.html">从ReentrantLock的实现看AQS的原理及应用.md.html</a>
</li>
<li>
<a href="/文章/从SpringCloud开始聊微服务架构.md.html">从SpringCloud开始聊微服务架构.md.html</a>
</li>
<li>
<a href="/文章/全面了解 JDK 线程池实现原理.md.html">全面了解 JDK 线程池实现原理.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性理论与算法.md.html">分布式一致性理论与算法.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性算法 Raft.md.html">分布式一致性算法 Raft.md.html</a>
</li>
<li>
<a href="/文章/分布式唯一 ID 解析.md.html">分布式唯一 ID 解析.md.html</a>
</li>
<li>
<a href="/文章/分布式链路追踪:集群管理设计.md.html">分布式链路追踪:集群管理设计.md.html</a>
</li>
<li>
<a href="/文章/动态代理种类及原理,你知道多少?.md.html">动态代理种类及原理,你知道多少?.md.html</a>
</li>
<li>
<a href="/文章/响应式架构与 RxJava 在有赞零售的实践.md.html">响应式架构与 RxJava 在有赞零售的实践.md.html</a>
</li>
<li>
<a href="/文章/大数据算法——布隆过滤器.md.html">大数据算法——布隆过滤器.md.html</a>
</li>
<li>
<a href="/文章/如何优雅地记录操作日志?.md.html">如何优雅地记录操作日志?.md.html</a>
</li>
<li>
<a href="/文章/如何设计一个亿级消息量的 IM 系统.md.html">如何设计一个亿级消息量的 IM 系统.md.html</a>
</li>
<li>
<a href="/文章/异步网络模型.md.html">异步网络模型.md.html</a>
</li>
<li>
<a href="/文章/当我们在讨论CQRS时我们在讨论些神马.md.html">当我们在讨论CQRS时我们在讨论些神马.md.html</a>
</li>
<li>
<a href="/文章/彻底理解 MySQL 的索引机制.md.html">彻底理解 MySQL 的索引机制.md.html</a>
</li>
<li>
<a href="/文章/最全的 116 道 Redis 面试题解答.md.html">最全的 116 道 Redis 面试题解答.md.html</a>
</li>
<li>
<a href="/文章/有赞权限系统(SAM).md.html">有赞权限系统(SAM).md.html</a>
</li>
<li>
<a href="/文章/有赞零售中台建设方法的探索与实践.md.html">有赞零售中台建设方法的探索与实践.md.html</a>
</li>
<li>
<a href="/文章/服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html">服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html</a>
</li>
<li>
<a href="/文章/深入浅出Cache.md.html">深入浅出Cache.md.html</a>
</li>
<li>
<a href="/文章/深入理解 MySQL 底层实现.md.html">深入理解 MySQL 底层实现.md.html</a>
</li>
<li>
<a href="/文章/漫画讲解 git rebase VS git merge.md.html">漫画讲解 git rebase VS git merge.md.html</a>
</li>
<li>
<a href="/文章/生成浏览器唯一稳定 ID 的探索.md.html">生成浏览器唯一稳定 ID 的探索.md.html</a>
</li>
<li>
<a href="/文章/缓存 如何保证缓存与数据库的双写一致性?.md.html">缓存 如何保证缓存与数据库的双写一致性?.md.html</a>
</li>
<li>
<a href="/文章/网易严选怎么做全链路监控的?.md.html">网易严选怎么做全链路监控的?.md.html</a>
</li>
<li>
<a href="/文章/美团万亿级 KV 存储架构与实践.md.html">美团万亿级 KV 存储架构与实践.md.html</a>
</li>
<li>
<a href="/文章/美团点评Kubernetes集群管理实践.md.html">美团点评Kubernetes集群管理实践.md.html</a>
</li>
<li>
<a href="/文章/美团百亿规模API网关服务Shepherd的设计与实现.md.html">美团百亿规模API网关服务Shepherd的设计与实现.md.html</a>
</li>
<li>
<a href="/文章/解读《阿里巴巴 Java 开发手册》背后的思考.md.html">解读《阿里巴巴 Java 开发手册》背后的思考.md.html</a>
</li>
<li>
<a href="/文章/认识 MySQL 和 Redis 的数据一致性问题.md.html">认识 MySQL 和 Redis 的数据一致性问题.md.html</a>
</li>
<li>
<a href="/文章/进阶Dockerfile 高阶使用指南及镜像优化.md.html">进阶Dockerfile 高阶使用指南及镜像优化.md.html</a>
</li>
<li>
<a href="/文章/铁总在用的高性能分布式缓存计算框架 Geode.md.html">铁总在用的高性能分布式缓存计算框架 Geode.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/面试最常被问的 Java 后端题.md.html">面试最常被问的 Java 后端题.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计在互联网业务开发中的实践.md.html">领域驱动设计在互联网业务开发中的实践.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计的菱形对称架构.md.html">领域驱动设计的菱形对称架构.md.html</a>
</li>
<li>
<a href="/文章/高效构建 Docker 镜像的最佳实践.md.html">高效构建 Docker 镜像的最佳实践.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>JVM 面试的 30 个知识点</h1>
<h1>1.什么是 Java 虚拟机?为什么 Java 被称作是“平台无关的编程语言”?</h1>
<p>Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机执行的字节码文件。Java 被设计成允许应用程序可以运行在任意的平台而不需要程序员为每一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。</p>
<h1>2.Java 内存结构?</h1>
<p><img src="assets/c5238280-5a00-11ea-aae6-17c0629b6dc0.jpg" alt="在这里插入图片描述" /></p>
<p>方法区和对是所有线程共享的内存区域;而 java 栈、本地方法栈和程序员计数器是运行是线程私有的内存区域。</p>
<h1>3.内存模型以及分区,需要详细到每个区放什么?</h1>
<p>JVM 分为堆区和栈区还有方法区初始化的对象放在堆里面引用放在栈里面class 类信息常量池static 常量和 static 变量)等放在方法区。 new:</p>
<ul>
<li>方法区主要是存储类信息常量池static 常量和 static 变量),编译后的代码(字节码)等数据</li>
<li>堆:初始化的对象,成员变量 (那种非 static 的变量),所有的对象实例和数组都要在堆上分配</li>
<li>栈:栈的结构是栈帧组成的,调用一个方法就压入一帧,帧上面存储局部变量表,操作数栈,方法出口等信息,局部变量表存放的是 8 大基础类型加上一个应用类型,所以还是一个指向地址的指针</li>
<li>本地方法栈:主要为 Native 方法服务</li>
<li>程序计数器:记录当前线程执行的行号</li>
</ul>
<h1>4.堆里面的分区Edensurvival from+ to老年代各自的特点</h1>
<p>堆里面分为新生代和老生代java8 取消了永久代,采用了 Metaspace新生代包含 Eden+Survivor 区survivor 区里面分为 from 和 to 区,内存回收时,如果用的是复制算法,从 from 复制到 to当经过一次或者多次 GC 之后,存活下来的对象会被移动到老年区,当 JVM 内存不够用的时候,会触发 Full GC清理 JVM 老年区当新生区满了之后会触发 YGC,先把存活的对象放到其中一个 Survice 区,然后进行垃圾清理。</p>
<p>因为如果仅仅清理需要删除的对象,这样会导致内存碎片,因此一般会把 Eden 进行完全的清理,然后整理内存。</p>
<p>那么下次 GC 的时候,就会使用下一个 Survive这样循环使用。</p>
<p>如果有特别大的对象,新生代放不下,就会使用老年代的担保,直接放到老年代里面。
因为 JVM 认为,一般大对象的存活时间一般比较久远。</p>
<h1>5 .解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法</h1>
<p>通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用 JVM 中的栈空间;而通过 new 关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为 Eden、Survivor又可分为 From Survivor 和 To Survivor、Tenured方法区和堆都是各个线程共享的内存区域用于存储已经被 JVM 加载的类信息、常量、静态变量、JIT 编译器编译后的代码等数据程序中的字面量literal如直接书写的 100、”hello”和常量都是放在常量池中常量池是方法区的一部分。栈空间操作起来最快但是栈很小通常大量的对象都是放在堆空间栈和堆的大小都可以通过 JVM 的启动参数来进行调整,栈空间用光了会引发 StackOverflowError而堆和常量池空间不足则会引发 OutOfMemoryError。</p>
<pre><code>String str = new String(&quot;hello&quot;);
</code></pre>
<p>上面的语句中变量 str 放在栈上,用 new 创建出来的字符串对象放在堆上而”hello”这个字面量是放在方法区的。</p>
<p>补充 1较新版本的 Java从 Java 6 的某个更新开始)中,由于 JIT 编译器的发展和”逃逸分析”技术的逐渐成熟,栈上分配、标量替换等优化技术使得对象一定分配在堆上这件事情已经变得不那么绝对了。</p>
<p>补充 2运行时常量池相当于 Class 文件常量池具有动态性Java 语言并不要求常量一定只有编译期间才能产生运行期间也可以将新的常量放入池中String 类的 intern()方法就是这样的。看看下面代码的执行结果是什么并且比较一下 Java 7 以前和以后的运行结果是否一致。</p>
<pre><code>String s1 = new StringBuilder(&quot;go&quot;)
.append(&quot;od&quot;).toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder(&quot;ja&quot;)
.append(&quot;va&quot;).toString();
System.out.println(s2.intern() == s2);
</code></pre>
<h1>6.GC 的两种判定方法?</h1>
<p>引用计数法:指的是如果某个地方引用了这个对象就+1如果失效了就-1当为 0 就 会回收但是 JVM 没有用这种方式因为无法判定相互循环引用A 引用 B,B 引用 A 的情况。
引用链法:通过一种 GC ROOT 的对象(方法区中静态变量引用的对象等-static 变 量)来判断,如果有一条链能够到达 GC ROOT 就说明,不能到达 GC ROOT 就说明 可以回收</p>
<h1>7.SafePoint 是什么?</h1>
<p>比如 GC 的时候必须要等到 Java 线程都进入到 safepoint 的时候 VMThread 才能开始执行 GC
1.循环的末尾 (防止大循环的时候一直不进入 safepoint而其他线程在等待它进入 safepoint)
2.方法返回前
3.调用方法的 call 之后
4.抛出异常的位置</p>
<h1>8.GC 的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?</h1>
<p>先标记,标记完毕之后再清除,效率不高,会产生碎片
复制算法:分为 81 的 Eden 区和 survivor 区,就是上面谈到的 YGC
标记整理:标记完毕之后,让所有存活的对象向一端移动</p>
<h1>9.GC 收集器有哪些CMS 收集器与 G1 收集器的特点?</h1>
<p>并行收集器串行收集器使用一个单独的线程进行收集GC 时服务有停顿时间
串行收集器:次要回收中使用多线程来执行
CMS 收集器是基于“标记—清除”算法实现的,经过多次标记才会被清除
G1 从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的</p>
<h1>10.Minor GC 与 Full GC 分别在什么时候发生?</h1>
<p>新生代内存不够用时候发生 MGC 也叫 YGCJVM 内存不够的时候发生 FGC</p>
<h1>11. 几种常用的内存调试工具jmap、jstack、jconsole、jhat</h1>
<p>jstack 可以看当前栈的情况jmap 查看内存jhat 进行 dump 堆的信息 mateclipse 的也要了解一下)</p>
<h1>12.什么是类的加载</h1>
<p>类的加载指的是将类的.class 文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class 对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的 Class 对象Class 对象封装了类在方法区内的数据结构,并且向 Java 程序员提供了访问方法区内的数据结构的接口。</p>
<h1>13.类加载器</h1>
<p><img src="assets/a3cc3370-5a00-11ea-8155-9d6d04886d5b.jpg" alt="在这里插入图片描述" /></p>
<ul>
<li>启动类加载器Bootstrap ClassLoader负责加载存放在 JDK\jre\lib(JDK 代表 JDK 的安装目录,下同)下,或被-Xbootclasspath 参数指定的路径中的,并且能被虚拟机识别的类库</li>
<li>扩展类加载Extension ClassLoader该加载器由 sun.misc.Launcher$ExtClassLoader 实现,它负责加载 DK\jre\lib\ext 目录中,或者由 java.ext.dirs 系统变量指定的路径中的所有类库(如 javax.*开头的类),开发者可以直接使用扩展类加载器。</li>
<li>应用程序类加载器Application ClassLoader该类加载器由 sun.misc.Launcher$AppClassLoader 来实现它负责加载用户类路径ClassPath所指定的类开发者可以直接使用该类加载器</li>
</ul>
<h1>14.描述一下 JVM 加载 class 文件的原理机制?</h1>
<p>JVM 中类的装载是由类加载器ClassLoader和它的子类来实现的Java 中的类加载器是一个重要的 Java 运行时系统组件,它负责在运行时查找和装入类文件中的类。</p>
<p>由于 Java 的跨平台性,经过编译的 Java 源程序并不是一个可执行程序,而是一个或多个类文件。当 Java 程序需要使用某个类时JVM 会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class 文件中的数据读入到内存中,通常是创建一个字节数组读入.class 文件,然后产生与所加载类对应的 Class 对象。加载完成后Class 对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后 JVM 对类进行初始化,包括:</p>
<ul>
<li>1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;</li>
<li>2)如果类中存在初始化语句,就依次执行这些初始化语句。</li>
</ul>
<p>类的加载是由类加载器完成的类加载器包括根加载器BootStrap、扩展加载器Extension、系统加载器System和用户自定义类加载器java.lang.ClassLoader 的子类)。</p>
<p>从 Java 2JDK 1.2开始类加载过程采取了父亲委托机制PDM。PDM 更好的保证了 Java 平台的安全性在该机制中JVM 自带的 Bootstrap 是根加载器其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载父类加载器无能为力时才由其子类加载器自行加载。JVM 不会向 Java 程序提供对 Bootstrap 的引用。下面是关于几个类加载器的说明:</p>
<ul>
<li>Bootstrap一般用本地代码实现负责加载 JVM 基础核心类库rt.jar</li>
<li>Extension从 java.ext.dirs 系统属性所指定的目录中加载类库,它的父加载器是 Bootstrap</li>
<li>System又叫应用类加载器其父类是 Extension。它是应用最广泛的类加载器。它从环境变量 classpath 或者系统属性 java.class.path 所指定的目录中记载类,是用户自定义加载器的默认父加载器。</li>
</ul>
<h1>15.Java 对象创建过程</h1>
<p>1.JVM 遇到一条新建对象的指令时首先去检查这个指令的参数是否能在常量池中定义到一个类的符号引用。然后加载这个类(类加载过程在后边讲)</p>
<p>2.为对象分配内存。一种办法“指针碰撞”、一种办法“空闲列表”,最终常用的办法“本地线程缓冲分配(TLAB)”</p>
<p>3.将除对象头外的对象内存空间初始化为 0</p>
<p>4.对对象头进行必要设置</p>
<h1>16.类的生命周期</h1>
<p>类的生命周期包括这几个部分,加载、连接、初始化、使用和卸载,其中前三部是类的加载的过程,如下图;</p>
<p><img src="assets/d2940fc0-5a00-11ea-a695-8f4c079b036d.jpg" alt="在这里插入图片描述" /></p>
<p>java 类加载需要经历以下 几个过程:</p>
<ul>
<li>加载</li>
</ul>
<p>加载时类加载的第一个过程,在这个阶段,将完成以下三件事情:</p>
<p>1.通过一个类的全限定名获取该类的二进制流。</p>
<p>2.将该二进制流中的静态存储结构转化为方法去运行时数据结构。</p>
<p>3.在内存中生成该类的 Class 对象,作为该类的数据访问入口。</p>
<ul>
<li>验证</li>
</ul>
<p>验证的目的是为了确保 Class 文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成以下四钟验证:</p>
<p>文件格式验证:验证字节流是否符合 Class 文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.</p>
<p>元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。</p>
<p>字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。 如: 方法中的类型转换是否正确,跳转指令是否正确等。</p>
<p>符号引用验证: 这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。</p>
<ul>
<li>准备</li>
</ul>
<p>准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。</p>
<pre><code>public static int value=123;
//在准备阶段 value 初始值为 0 。
在初始化阶段才会变为 123。
</code></pre>
<ul>
<li>解析</li>
</ul>
<p>该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。</p>
<ul>
<li>初始化</li>
</ul>
<p>初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。 到了初始化阶段,才真正开始执行类中定义的 Java 程序。</p>
<h1>17.简述 java 类加载机制?</h1>
<p>虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的 java 类型。</p>
<h1>18.Java 对象结构</h1>
<p>Java 对象由三个部分组成:对象头、实例数据、对齐填充。</p>
<p>对象头由两部分组成第一部分存储对象自身的运行时数据哈希码、GC 分代年龄、锁标识状态、线程持有的锁、偏向线程 ID一般占 32/64 bit</p>
<p>第二部分是指针类型,指向对象的类元数据类型(即对象代表哪个类)。如果是数组对象,则对象头中还有一部分用来记录数组长度。</p>
<p>实例数据用来存储对象真正的有效信息(包括父类继承下来的和自己定义的)</p>
<p>对齐填充JVM 要求对象起始地址必须是 8 字节的整数倍8 字节对齐)</p>
<h1>19.Java 对象的定位方式</h1>
<p>句柄池、直接指针。</p>
<h1>20.如和判断一个对象是否存活?(或者 GC 对象的判定方法)</h1>
<p>判断一个对象是否存活有两种方法:</p>
<p>1.引用计数法</p>
<p>所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一。当一个对象的引用计数器为零时,说明此对象没有被引用,也就是“死对象”,将会被垃圾回收。 引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象 A 引用对象 B对象 B 又引用者对象 A那么此时 A,B 对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法。</p>
<p>2.可达性算法(引用链法)</p>
<p>该算法的思想是:从一个被称为 GC Roots 的对象开始向下搜索,如果一个对象到 GC Roots 没有任何引用链相连时,则说明此对象不可用。
在 java 中可以作为 GC Roots 的对象有以下几种:
虚拟机栈中引用的对象</p>
<p>方法区类静态属性引用的对象</p>
<p>方法区常量池引用的对象</p>
<p>本地方法栈 JNI 引用的对象</p>
<p>虽然这些算法可以判定一个对象是否能被回收,但是当满足上述条件时,一个对象比不一定会被回收。当一个对象不可达 GC Root 时,这个对象并不会立马被回收,而是出于一个死缓的阶段,若要被真正的回收需要经历两次标记如果对象在可达性分析中没有与 GC Root 的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行 finalize()方法。当对象没有覆盖 finalize()方法或者已被虚拟机调用过,那么就认为是没必要的。</p>
<p>如果该对象有必要执行 finalize()方法,那么这个对象将会放在一个称为 F-Queue 的对队列中,虚拟机会触发一个 Finalize()线程去执行,此线程是低优先级的,并且虚拟机不会承诺一直等待它运行完,这是因为如果 finalize()执行缓慢或者发生了死锁,那么就会造成 FQueue 队列一直等待,造成了内存回收系统的崩溃。 GC 对处于 F-Queue 中的对象进行第二次被标记,这时,该对象将被移除”即将回收”集合,等待回收。</p>
<h1>21.JVM 的永久代中会发生垃圾回收么?</h1>
<p>垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免 Full GC 是非常重要的原因。请参考下 Java8从永久代到元数据区 (注Java8 中已经移除了永久代,新加了一个叫做元数据区的 native 内存区)</p>
<h1>22.简述 java 内存分配与回收策率以及 Minor GC 和 Major GC</h1>
<p>1.对象优先在堆的 Eden 区分配。</p>
<p>2.大对象直接进入老年代.</p>
<p>3.长期存活的对象将直接进入老年代.,当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC.Minor Gc 通常发生在新生代的 Eden 区,在这个区的对象生存期短,往往发生 Gc 的频率较高, 回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代 GC 的时候不会触发 Minor GC,但是通过配置,可以在 Full GC 之前进行一次 MinorGC 这样可以加快老年代的回收速度。</p>
<h1>23.判断一个对象应该被回收</h1>
<p>该对象没有与 GC Roots 相连</p>
<p>该对象没有重写 finalize()方法或 finalize()已经被执行过则直接回收(第一次标记)、否则将对象加入到 F-Queue 队列中(优先级很低的队列)在这里 finalize()方法被执行,之后进行第二次标记,如果对象仍然应该被 GC 则 GC否则移除队列。在 finalize 方法中,对象很可能和其他 GC Roots 中的某一个对象建立了关联finalize 方法只会被调用一次,且不推荐使用 finalize 方法)</p>
<h1>24.回收方法区</h1>
<p>方法区回收价值很低,主要回收废弃的常量和无用的类。</p>
<p>如何判断无用的类:</p>
<p>该类所有实例都被回收Java 堆中没有该类的对象)</p>
<p>加载该类的 ClassLoader 已经被回收</p>
<p>该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方利用反射访问该类</p>
<h1>25.垃圾收集算法</h1>
<p>GC 最基础的算法有三种:标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收器一般都采用分代收集算法。</p>
<ul>
<li>标记 -清除算法,“标记-清除”Mark-Sweep算法如它的名字一样算法分为“标记”和“清除”两个阶段首先标记出所有需要回收的对象在标记完成后统一回收掉所有被标记的对象。</li>
<li>复制算法“复制”Copying的收集算法它将可用内存按容量划分为大小相等的两块每次只使用其中的一块。当这一块的内存用完了就将还存活着的对象复制到另外一块上面然后再把已使用过的内存空间一次清理掉。</li>
<li>标记-压缩算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存</li>
<li>分代收集算法“分代收集”Generational Collection算法把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。</li>
</ul>
<h1>26.垃圾回收器</h1>
<p>Serial 收集器,串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。</p>
<p>ParNew 收集器ParNew 收集器其实就是 Serial 收集器的多线程版本。</p>
<p>Parallel 收集器Parallel Scavenge 收集器类似 ParNew 收集器Parallel 收集器更关注系统的吞吐量。</p>
<p>Parallel Old 收集器Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法</p>
<p>CMS 收集器CMSConcurrent Mark Sweep收集器是一种以获取最短回收停顿时间为目标的收集器。</p>
<p>G1 收集器G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征</p>
<h1>27.GC 日志分析</h1>
<p>摘录 GC 日志一部分(前部分为年轻代 gc 回收;后部分为 full gc 回收):</p>
<pre><code>2016-07-05T10:43:18.093+0800: 25.395: [GC [PSYoungGen: 274931K-&gt;10738K(274944K)] 371093K-&gt;147186K(450048K), 0.0668480 secs] [Times: user=0.17 sys=0.08, real=0.07 secs]
2016-07-05T10:43:18.160+0800: 25.462: [Full GC [PSYoungGen: 10738K-&gt;0K(274944K)] [ParOldGen: 136447K-&gt;140379K(302592K)] 147186K-&gt;140379K(577536K) [PSPermGen: 85411K-&gt;85376K(171008K)], 0.6763541 secs] [Times: user=1.75 sys=0.02, real=0.68 secs]
</code></pre>
<p>通过上面日志分析得出PSYoungGen、ParOldGen、PSPermGen 属于 Parallel 收集器。其中 PSYoungGen 表示 gc 回收前后年轻代的内存变化ParOldGen 表示 gc 回收前后老年代的内存变化PSPermGen 表示 gc 回收前后永久区的内存变化。young gc 主要是针对年轻代进行内存回收比较频繁耗时短full gc 会对整个堆内存进行回城,耗时长,因此一般尽量减少 full gc 的次数</p>
<h1>28.调优命令</h1>
<p>Sun JDK 监控和故障处理命令有 jps jstat jmap jhat jstack jinfo</p>
<ul>
<li>jpsJVM Process Status Tool,显示指定系统内所有的 HotSpot 虚拟机进程。</li>
<li>jstatJVM statistics Monitoring 是用于监视虚拟机运行时状态信息的命令它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。</li>
<li>jmapJVM Memory Map 命令用于生成 heap dump 文件</li>
<li>jhatJVM Heap Analysis Tool 命令是与 jmap 搭配使用,用来分析 jmap 生成的 dumpjhat 内置了一个微型的 HTTP/HTML 服务器,生成 dump 的分析结果后,可以在浏览器中查看</li>
<li>jstack用于生成 java 虚拟机当前时刻的线程快照。</li>
<li>jinfoJVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。</li>
</ul>
<h1>29.调优工具</h1>
<p>常用调优工具分为两类,jdk 自带监控工具jconsole 和 jvisualvm第三方有MAT(Memory Analyzer Tool)、GChisto。</p>
<p>jconsoleJava Monitoring and Management Console 是从 java5 开始,在 JDK 中自带的 java 监控和管理控制台,用于对 JVM 中内存,线程和类等的监控</p>
<p>jvisualvmjdk 自带全能工具可以分析内存快照、线程快照监控内存变化、GC 变化等。</p>
<p>MATMemory Analyzer Tool一个基于 Eclipse 的内存分析工具,是一个快速、功能丰富的 Java heap 分析工具,它可以帮助我们查找内存泄漏和减少内存消耗</p>
<p>GChisto一款专业分析 gc 日志的工具</p>
<h1>30.Minor GC 与 Full GC 分别在什么时候发生?</h1>
<p>新生代内存不够用时候发生 MGC 也叫 YGCJVM 内存不够的时候发生 FGC</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/文章/JVM 垃圾收集器.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/文章/Java IO 体系、线程模型大总结.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997faf2d7f8b66","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>