JVM内存区域详解,一文弄懂JVM内存【内存分布、回收算法、垃圾回收器】
视频讲解地址
学习文档
一、内存区域
区域 | 描述 | 线程私有 | 如何溢出 |
---|---|---|---|
程序计数器 | 为了线程切换后能恢复到正确的执行位置,每个线程都要有一个独立的程序计数器。 | ✅ | 唯一一个不会内存溢出的地方 |
虚拟机栈 | 1. 每个方法执行的时候,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、方法出口等信息。 2. 每一个方法从调用到执行完毕都对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 3. 局部变量表存储了编译期可知的各种Java基本数据类型和对象引用。 | ✅ | 1. 线程请求的栈深度大于虚拟机所允许的深度时抛出 StackOverFlowError异常。 2. 栈扩容时无法申请到足够内存的时候抛出 OutOfMemoryError。 |
本地方法栈 | 和虚拟机栈类似,本地方法栈是为本地(Native)方法服务的 | ✅ | 同【虚拟机栈】 |
方法区 | 线程共享,用于存放被虚拟机加载后的类型信息、常量、静态变量、即时编译器编译后的代码缓存数据。 注:运行时常量池、元空间都属于方法区的一部分。 | ❌ | 无法满足新的内存分配会抛出 OutOfMemoryError |
堆(垃圾收集的主要区域) | 1. 基本上所有的对象都是在堆上分配的。 2. Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。 | ❌ | 无法满足新的内存分配会抛出 OutOfMemoryError |
直接内存 | NIO通过使用Native函数库直接分配对外内存。不受Java堆大小限制,但是受机器的物理内存限制。 | ❌ | 无法满足新的内存分配会抛出 OutOfMemoryError |
堆其实就是一大块内存区域,是用来存放对象的,对于一个应用来说最耗费内存的就是“对象”。因为在运行的过程中会创建无数个对象,所以内存回收(垃圾回收)的时候主要就是针对堆的垃圾进行回收。
常见的堆划分是:
- 把堆分为新生代和老年代
- 新生代分为一个Eden区和两个Survivor区,它们的内存占比是 8:1:1
- 注:但G1却不是这样的,它把堆分成数个大小相同的Regin块
二、回收时机
上面我们谈到内存空间,内存是有限的,想要健康持续的运行下去,就一定要回收“垃圾”。
那怎么判定一个对象是不是垃圾呢,就成了新的问题。
算法 | 描述 | 备注 |
---|---|---|
引用计数算法 | 当某个对象被引用的时候引用计数器就加一,引用失效时就减一,当没有引用的时候就说明可以被回收了。 | 几乎没有使用它的,因为它无法解决循环依赖的问题。 |
可达性分析 | 某些对象被定义为根(GC Roots),从GC Roots向下搜索的路径成为“引用链”,如果某个对象到GC Roots间没有任何引用,那说明它不可达,它就可以被回收了。 | 目前都是用这种算法。 |
GC Roots并不是一个固定的对象,它是一组对象:
- 在虚拟机栈引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
- 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
- 在方法区中常量引用的对象,譬如字符串常量池里的引用。
- 在本地方法栈中JNI(即 Native方法)引用的对象。
- Java虚拟机内部的引用,如基本数据类型对应的Class对象。
- 所有被同步锁(Sync)持有的对象。
- 除了这些固定的GC Roots,根据不同的垃圾回收器还可以有其他“临时性”地加入。
一个对象是否可以被回收,是要看有没有被GC Roots触达,而不是仅仅是 触达
不管是引用计数算法,还是可达性分析,都提到了引用。Java中的引用并不是简单的引用,它有四种不同的引用
引用类型 | 描述 |
---|---|
强引用 | 被强引用的对象不会被回收。 new 的方式创建就是产生强引用。 |
软引用 | 被软应用的对象,只有在内存不足的时候才会被回收。 |
弱引用 | 被弱引用的对象,在下一次垃圾回收的时候就会被回收。 |
虚引用 | 虚引用又被称为幽灵引用,它和回收没太大关系,只是在回收的时候,会收到一个系统的通知。 |
三、回收算法
已经知道了哪些对象是可以回收的,那就需要按照某种回收算法,去回收它们。
名称 | 描述 | 优缺点 |
---|---|---|
标记-清除 | 标记所有未被引用的对象,在GC的时候清空它们。 | 优点:简单直观 缺点:会产生大量的内存碎片。如果下次需要分配一个大对象,没有连续空间的时候会提前触发GC。 |
标记-整理 | 标记所有被引用的对象,将还存活的对象移动到一端,然后清除边界外的内存。 | 优点:减少了内存碎片,相对于标记-清除减少了碎片化问题。 缺点:移动对象需要成本。 |
标记-复制 | 将内存划分成两个相同大小的块,每次只使用其中一块。当一块的内存用完了,就将还存活的对象复制到另外一块,然后再把之前那块空间清空。 IBM公司有一项研究的结论是:新生代中98%的对象熬不过第一轮回收,所以不必按照 1:1 的比例来划分。 新生代分为三个区:一个Eden、两个Survivor,对象优先分配在Eden区,每次只使用Eden和一个Survivor,在垃圾回收的时候把还存活的对象移动到另外一个没有被使用的Survivor中。如果Survivor区空间不够,会把对象移动到老年代。 注 1. 两个Survivor,在有的地方被称为From和 To,或 S0、S1 2. 默认情况下Eden和两个Survivor的比例是 8:1:1 | 优点:减少了内存碎片,适用于对象生命周期短的场景。 缺点:空间浪费和复制成本。 |
四、回收器
回收算法是理论,回收器是实践,不同回收器都是基于理论进行真正的实践,在讨论回收器之前需要先了解下面几个点
- STW:Stop The World 的缩写,意味着在GC的时候,其它线程无法工作。
- 并行、并发:多个GC线程一起工作就是并行,GC线程和用户线程一起工作就是并发。
- 吞吐量:运行用户代码时间 / 运行用户代码时间+垃圾回收时间,通过算法可以得出想要提高吞吐量,就必须减少垃圾回收耗时。
下面是各个回收器的作用域,连线表示它们可以组合使用,红色线表示JDK9已经不推荐了。
名称 | 描述 | 效率 | STW | 回收算法 | 作用域 | 目标 | 使用场景 | 回收步骤 |
---|---|---|---|---|---|---|---|---|
Serial | 它是单线程工作的,且在进行垃圾回收的时候,必须暂停所有的工作线程。 | 串行 | 是 | 标记-复制 | 新生代 | 快速的回收 | 1. 在客户端模式下的默认新生代收集器。 2. 对于内存资源不多的情况下,它是所有收集器里额外内存消耗最小的。 | ![]() |
Serial Old | 同上 | 串行 | 是 | 标记-整理 | 老年代 | 快速的回收 | 同上 | 同上 |
ParNew | 它支持多线程并行回收垃圾,其它与Serial收集器没什么大的差别。 | 并行 | 是 | 标记-复制 | 新生代 | 快速的回收 | 是除了Serial之外唯一可以和CMS收集器配合工作的。 | ![]() |
Parallel Scavenge | 它和ParNew有很多相似的地方,不同的是它关注的是 达到一个可控制的吞吐量。 | 并行 | 是 | 标记-复制 | 新生代 | 提高吞吐量 | 大规模的后台服务、批处理任务等,对吞吐量要求高的场景。 | 同上 |
Parallel Old | 同上 | 并行 | 是 | 标记-整理 | 老年代 | 提高吞吐量 | 同上 | 同上 |
CMS | CMS可以并发的去执行,并且可以部分STW的回收器。 | 并发 | 部分STW | 标记-清除 | 老年代 | 快速的回收 | 对延迟敏感的应用,需要较短垃圾回收停顿时间。 | ![]() |
G1 | 1. G1将堆分成多个大小相同的Regin(大小在 1-32MB,默认是 2048个),每一个Regin都可以充当新生代或老年代中的某个区。 2. Regin中还有一个特殊的区域 Humongous Regin(大对象直接分在老年代,防止了反复拷贝移动) ,G1规定大小超过普通Regin一半的对象是大对象,大对象就存在Humongous Regin,它会独占一个、或多个连续Region。 3. 使用 Mixed GC 回收(下面讲) | 并发 | 部分STW | 标记-整理 | 通吃 | 满足高吞吐量的同时,尽可能地减少垃圾回收耗时 | 大内存应用、需要可预测停顿时间的应用,JDK9开始成为默认的垃圾回收器。 | G1对于CMS并不是完全的碾压,G1的实现更加复杂,所以它所额外使用的内存和程序运行时的负载都比CMS高。 |
CMS和G1的对比
- CMS会产生内存碎片,且无法回收浮动垃圾(因为清理的时候是并发的,这时候工作线程可能产生新的垃圾)
- 关注点:CMS是快速的回收,G1是在限定的时间内(这个时间可以自定义),最大限度的回收(会把垃圾排序然后回收收益最大的部分)
- 作用范围:CMS是作用于老年代,G1是都可以
- 内存分布:G1对堆内存进行了大小相同的Regin划分,在Regin的基础上再进行新生代和老年代划分,CMS是传统的新生代、老年代分布
- 性能:CMS对CPU资源非常敏感可能会影响正常请求(因为回收的时候很多阶段是并发的),G1对内存要求较高(想想它对堆做了那么复杂的划分和逻辑,这些都是需要额外内存和cup支持的),所以更适合大堆
- G1的目的是代替CMS,JDK9之后默认的垃圾收集器就是G1,但CMS并不是一无是处,在内存小的时候还是更合适的
MinorGC、MajorGC、Full GC、Mixed GC
- MinorGC:是对新生代回收时候的GC,有时候也叫 youngGC
- MajorGC:是针对老年代的垃圾回收操作。出现 Major GC 通常会出现至少一次 Minor GC。有时候也叫 OldGC
- Full GC:Full GC 会清理整个堆和方法区,包括年轻代、老年代和方法区。FullGC对于方法区的回收主要是满足下面三个条件
-
- Java堆中不存在该类的任何实例对象;
-
- 加载该类的类加载器已经被回收;
-
- 该类对应的java.lang.Class对象不在任何地方被引用,且无法在任何地方通过反射访问该类的方法。
- Mixed GC:它是G1才有的。不再是每次回收新生代、老年代了,而是把内存排序后,回收利益最大的,这也是G1这个名字的由来。
五、其它
注:G1并不是终点,后面还有ZGC它关注更低的延迟,但现在大家都还没用到,暂时先不去学习了
参考:
- 本文严重参考了《深入理解Java虚拟机》这本书
- https://tech.meituan.com/2016/09/23/g1.html
相关文章:

JVM内存区域详解,一文弄懂JVM内存【内存分布、回收算法、垃圾回收器】
视频讲解地址 学习文档 一、内存区域 区域描述线程私有如何溢出程序计数器为了线程切换后能恢复到正确的执行位置,每个线程都要有一个独立的程序计数器。✅唯一一个不会内存溢出的地方虚拟机栈1. 每个方法执行的时候,Java虚拟机都会同步创建一个栈帧用于…...

uniapp搜索附近蓝牙信标(iBeacon)
一、 iBeacon介绍 iBeacon是苹果在2013年WWDC上推出一项基于蓝牙4.0(Bluetooth LE | BLE | Bluetooth Smart)的精准微定位技术,在iPhone 4S后支持。当你的手持设备靠近一个Beacon基站时,设备就能够感应到Beacon信号,范…...

Redis 常见数据结构以及使用场景分析
Java面试题目录 Redis 常见数据类型以及使用场景分析 Redis中有string、list、hash、set、sorted set、bitmap这6种数据类型。 string可以用来做缓存,分布式锁,计数器等。 list可以实现消息队列,分页查询等。 hash适合存储对象结构。 set 可…...

LMDeploy 大模型量化部署实践
LMDeploy 大模型量化部署实践 大模型部署背景模型部署定义产品形态计算设备 大模型特点大模型挑战大模型部署方案 LMDeploy简介推理性能核心功能-量化核心功能-推理引擎TurboMind核心功能 推理服务 api-server 案例(安装、部署、量化) 大模型部署背景 模型部署 定义 将训练好…...

15个为你的品牌增加曝光的维基百科推广方法-华媒舍
维基百科是全球最大的免费在线百科全书,拥有庞大的用户群体和高质量的内容。在如今竞争激烈的市场中,利用维基百科推广品牌和增加曝光度已成为许多企业的重要策略。本文将介绍15种方法,帮助你有效地利用维基百科推广品牌,提升曝光…...

启动redis出现Creating Server TCP listening socket 127.0.0.1:6379: bind: No error异常
1.进入redis安装目录,地址栏输入cmd 2.输入命令 redis-server.exe redis.windows.conf redis启动失败 解决,输入命令 #第一步 redis-cli.exe#第二步 shutdown#第三步 exit第四步 redis-server.exe redis.windows.conf 显示以下图标即成功...

响应式编程Reactor优化Callback回调地狱
1. Reactor是什么 Reactor 是一个基于Reactive Streams规范的响应式编程框架。它提供了一组用于构建异步、事件驱动、响应式应用程序的工具和库。Reactor 的核心是 Flux(表示一个包含零到多个元素的异步序列)和 Mono表示一个包含零或一个元素的异步序列…...

React项目实战--------极客园项目PC端
项目介绍:主要将学习到的项目内容进行总结(有需要项目源码的可以私信我) 关于我的项目的配置如下,请注意下载的每个版本不一样,写的api也不一样 一、项目介绍 1.资料 1)短信接收&M端演示:…...

Jerry每次能向前或向后走n*n步(始终不能超过初始位置1e5),q(q <= 1e5)次询问,求向前走d最少要几次
题目 思路:因为有走的过程不能超初始位置1e5的限制,所以不能直接用奇数最多两次,4的倍数最多两次的结论。spfa,平方数的dis为1,然后推出其他数的dis #include<bits/stdc.h> using namespace std; #define int …...

【Spring Boot 3】【Flyway】数据库版本管理
【Spring Boot 3】【Flyway】数据库版本管理 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是…...

蓝桥杯基础数据结构(java版)
引言 数据结构数据结构。所以数据结构是一个抽象的概念。其目的是为了更好的组织数据方便数据存储。下面我们来看一些简单的数据储存方式 输入和输出 这里先介绍java的输入和输出。简单引入,不过多详细介绍,等我单一写一篇的时候这里会挂上链接 简单的…...

39 C++ 模版中的参数如果 是 vector,list等集合类型如何处理呢?
在前面写的例子中,模版参数一般都是 int,或者一个类Teacher,假设我们现在有个需求:模版的参数要是vector,list这种结合类型应该怎么写呢? //当模版中的类型是 vector ,list 等集合类型的时候的处…...

5.Pytorch模型单机多GPU训练原理与实现
文章目录 Pytorch的单机多GPU训练1)多GPU训练介绍2)pytorch中使用单机多GPU训练DistributedDataParallel(DDP)相关变量及含义a)初始化b)数据准备c)模型准备d)清理e)运行 3)使用DistributedDataParallel训练模型的一个简单实例 欢迎访问个人网络日志🌹🌹知…...

想成为一名C++开发工程师,需要具备哪些条件?
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保…...

Qat++,轻量级开源C++ Web框架
目录 一.简介 二.编译Oat 1.环境 2.编译/安装 三.试用 1.创建一个 CMake 项目 2.自定义客户端请求响应 3.将请求Router到服务器 4.用浏览器验证 一.简介 Oat是一个面向C的现代Web框架 官网地址:https://oatpp.io github地址:https://github.co…...

openssl3.2 - 官方demo学习 - digest - EVP_MD_demo.c
文章目录 openssl3.2 - 官方demo学习 - digest - EVP_MD_demo.c概述笔记END openssl3.2 - 官方demo学习 - digest - EVP_MD_demo.c 概述 使用 SHA3-512 对多个buffer连续进行摘要, 最后得到一个摘要值 笔记 /*! \file EVP_MD_demo.c \note openssl3.2 - 官方demo学习 - dig…...

uniapp 编译后文字乱码的解决方案
问题: 新建的页面中编写代码,其中数字和图片都可以正常显示,只有中文编译后展示乱码 页面展示也是乱码 解决方案: 打开HuilderX编辑器的【文件】- 【以指定编码重新打开】- 【选择UTF-8】 然后重新编译就可以啦~ 希望可以帮到你啊~...

iOS中利用KeyChain永久保存用户信息的方法示例
方法示例 一、新建一个LYKeychainTool类,导入系统Security框架 ,LYKeychainTool.h文件实现如下 // // LYKeychainTool.h // keyChainTest // // Created by Liyu on 2017/6/2. // Copyright © 2017年 liyu. All rights reserved. //#import <F…...

基于时域有限差分法的FDTD的计算电磁学算法(含Matlab代码)-YEE网格下的更新公式推导
基于时域有限差分法的FDTD的计算电磁学算法(含Matlab代码)-YEE网格下的更新公式推导 参考书籍:The finite-difference time-domain method for electromagnetics with MATLAB simulations(国内翻译版本:MATLAB模拟的电…...

win10使用debug,汇编初学
DOSBox挂载Debug.exe 双击 DOSBox Options.bat 打开配置 或者执行cmd DOSBox.exe -editconf notepad.exe -editconf %SystemRoot%\system32\notepad.exe -editconf %WINDIR%\notepad.exe最后一行增加 mount [盘符] [挂载的工作目录(debug.exe文件夹位置ÿ…...

怎么投稿各大媒体网站?
怎么投稿各大媒体网站?这是很多写作者及自媒体从业者经常面临的问题。在信息爆炸的时代,如何将自己的文章推送到广大读者面前,成为了一个不可避免的挑战。本文将为大家介绍一种简单有效的投稿方法——媒介库发稿平台发稿,帮助大家…...

chatgpt免费使用的网站
前言 如果您认为本文对你有帮助,希望可以点赞收藏!感谢您的支持 下面我为你推荐我自己在用的gpt类工具,帮你在工作学习生活上解决一些大小问题 🎉智能GPT 地址: https://meet.adminjs.net 在他的详情中有详细的使用…...

音频编辑软件:Studio One 6 中文
Studio One 6是一款功能强大的数字音乐制作软件,为用户提供一站式音乐制作解决方案。它具有直观的界面和强大的音频录制、编辑、混音和制作功能,支持虚拟乐器、效果器和第三方插件,可帮助用户实现高质量的音乐创作和制作。同时,St…...

MySQL语句|使用UNION和UNION ALL合并两个或多个 SELECT 语句的结果集
文章目录 举个通用的例子举个实际的例子 在MySQL中, UNION 和 UNION ALL 是用于合并两个或多个 SELECT 语句的结果集的操作符。 UNION 会去除结果集中的重复行,返回唯一的行,而 UNION ALL 会返回所有的行,包括重复行。 举个通…...

UNRAID 优盘制作
使用方法和开心方法: 如果重启之后显示器有信号但是黑屏无法正常引导系统,此为九代以后主板快速开机(快速引导)UNRAID并不支持快速引导所以会直接卡黑屏。所以发现这种情况的时候请进BIOS关闭和开机快速引导或和快有关系的任何开…...

二、Java中SpringBoot组件集成接入【MySQL和MybatisPlus】
二、Java中SpringBoot组件集成接入【MySQL和MybatisPlus】 1.MySQL和MybatisPlus简介2.maven依赖3.配置1.在application.yaml配置中加入mysql配置2.新增Mybatis-Plus配置类 4.参考文章 1.MySQL和MybatisPlus简介 MySQL是一种开源的关系型数据库管理系统,被广泛应用…...

银行测试--------转账
转账 付款账号测试 付款账号是借记卡,也可以是活期存折信用卡,定期存折不能转出。一般在账号选择的时候进行屏蔽转出账户在销户,冻结,挂失等异常状态,不能进行转账付款账号金额不够 转账金额测试 0.01~…...

阿里云最新优惠券领取方法及优惠活动汇总
随着互联网的飞速发展,云服务已经成为企业和个人使用的重要基础设施。阿里云作为全球领先的云服务提供商,一直致力于为用户提供优质的云服务。为了回馈用户,阿里云会定期推出各种优惠券和优惠活动,本文将为大家介绍阿里云最新优惠…...

动态分配内存的风险
1. 悬挂指针问题 在指针释放之后要将指针置空 delete ptr; ptr nullptr;2.内存碎片问题 频繁的申请与释放小块内存会造成大量的内存碎片。 3.内存申请与释放问题 C与C的内存申请与释放最好不要混用。 4.复制内存 基本语法 void* memcpy(void* _Dst, void* _Src, size_…...

多行SQL转成单行SQL
如下图所示 将以上多行SQL转成单行SQL 正则表达式如下 (?s)$[^a-zA-Z()0-9]*结果如下 灵活使用,也未必只能使用Sublime Text...