当前位置: 首页 > news >正文

[java基础-JVM篇]1_JVM自动内存管理

JVM内存管理涉及但不限于类加载、对象分配、垃圾回收等,本篇主要记录运行时数据区域与对象相关内容。
内容主要来源《深入理解Java虚拟机:JVM高级特性与最佳实践》与官方文档,理解与表述错漏之处恳请各位大佬指正。

目录

运行时数据区域

栈帧

栈异常

栈内存大小配置

配置参数

配置参数

字符串常量池(注意,字符串常量池自jdk8起在堆)

静态变量特别说明

方法区

运行时常量池

常量说明

常量分析实例

配置参数

程序计数器

直接内存

总结

对象

对象创建

内存分配(更新操作)的原子性原理

对象访问

内存泄漏分析(生产)

大对象

大对象的影响

解决


运行时数据区域

内存管理基于:内存动态分配与垃圾收集技术。
编译期间做的事情:给变量分配空间

一般讲的都是虚拟机栈,更多情况下指虚拟机栈中局部变量表部分。本地方法栈执行的都是本地的Native方法。

栈帧

每个线程都有自己的虚拟机栈,而方法作为执行的基本单元,在 每个方法执行的时候都会创建一个栈帧Stack Frame用于存储局部变量表、操作数栈、动态连接、方法出口信息等。
其中 局部变量表存放了编译期可知的 基本数据类型、对象引用
(了解就行)栈帧中存储的具体信息包括:
  1. 方法参数:包括传递给方法的实际参数以及方法的隐式参数,如 this 指针。
  2. 局部变量:定义在方法中的变量,包括基本类型和对象引用。
  3. 操作数栈:用于存储方法执行过程中产生的临时数值,如算术运算的结果、方法调用的返回值等。
  4. 方法返回地址:指向方法调用者应该返回的下一条指令的地址。
  5. 异常处理器:存储方法对应的异常处理器的信息,用于处理方法执行中可能发生的异常。
  6. 其它:包括方法的访问标志、常量池引用等。

栈异常

StackOverflowError
栈溢出
OutOfMemoryError
对于栈的提示是 java.lang.OutOfMemoryError: unable to create new native thread。此时无法创建新线程

栈内存大小配置

HotSpot虚拟机的栈容量不可动态拓展,在配置JVM时通过-参数Xss=256k配置。
JVM的总内存大小会影响线程栈内存的可用量。如果堆内存或者其他内存区域占用过多,剩余内存可能不足以支持大量线程。

配置参数

-Xss栈大小设置,在64位Linux系统上,栈大小默认1M

是垃圾回收管理器管理的区域,储物理上可以不连续,逻辑上是连续的内存空间。因垃圾收集器基于分代收集理论设计,所以将 分代划分(方便回收和分配内存)。
“新生代、老年代、Eden空间、From Survivor空间、To Survivor空间”。
堆:1:2=新生代:老年代, 其中新生代8:1:1 eden:from:to
存放几乎所有对象实例与数组(基本类型数组与对象类型数组)、字符串常量、静态变量。

配置参数

-Xms堆内存起始大小 -Xmx最大堆内存

字符串常量池(注意,字符串常量池自jdk8起在堆)

专门用于存储字符串字面量的一个特殊区域。它的设计目的是通过缓存机制避免重复创建相同的字符串对象,从而节省内存并提高性能。
值得注意的是,HotSpotJVM自JDK8将字符串常量池实现为堆中的一部分,从方法区移出,以优化内存管理并减少方法区的压力。
资料来源:
JEP 122: Remove the Permanent Generation
Chapter 5. Loading, Linking, and Initializing

静态变量特别说明

有资料说在方法区、有资料说在堆,给我整不会了。直接看官网
JEP 122: Remove the Permanent Generation
结论:静态变量引用或基本类型值静态变量在元空间,对象实例(包括静态对象的值)在堆中

方法区

方法区也是线程共享的内存区域,主要用于存储已被虚拟机加载的 类型信息、静态变量对象的引用与基本类型静态变量、即时编译器编译后的代码缓存等数据。是基于本地内存实现的,方法区内存回收主要目标是常量池的回收和对类型的卸载

运行时常量池

运行时常量池是方法区的一部分,是常量池表(Class文件常量池)运行时的表示形式,其中常量池表存储的是 符号引用(Symbolic References)和 字面量(Literal Values),而 不是实际的数据存储位置。它的核心作用是:
  • 存储类、方法、字段的全限定名描述
  • 保存方法描述符(Descriptor)
  • 存储字符串常量字面量
  • 记录数值型常量的原始值

常量说明

在代码中,使用final声明的常量会放到方法区运行时常量池
方法内变量=临时变量,存储在虚拟机栈中

常量分析实例

配置参数

-XX:MetaspaceSize:初始触发 GC 的阈值,默认约 21MB。
-XX:MaxMetaspaceSize:最大大小,默认无上限(受本地内存限制)。
-XX:MinMetaspaceFreeRatio 和 -XX:MaxMetaspaceFreeRatio:控制 GC 后空闲比例,默认 40% 和 70%。

程序计数器

作为游标指示字节码命令执行,每个线程的程序计数器是独立的。
计数器的值是正在执行的虚拟机字节码指令的地址。

直接内存

直接内存是指Java应用程序在JVM堆之外直接向操作系统申请并管理的一段内存区域。堆外内存的一种具体实现形式。
使用Native函数分配的堆外内存,用与NIO等操作。
设置虚拟机内存时,需要小于物理内存(给直接内存留空间)。因为运行时JVM内存=设置的内存+直接内存,实际占用的比设置的要大。防止动态扩展时出现OutOfMemoryError异常。
堆外内存通过DirectByteBuffer进行操作,避免在Java堆中和Native堆中来回复制数据。
需要注意的就是物理内存应该>jvm内存

总结

对象

对象可以划分为:对象头(Header)、实例数据(Instance)、对齐填充(Padding).
对象头包括两类信息。一部分包括对象自行运行时数据:哈 希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部 分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32个比特和64个比特,官方称它 为“Mark Word”。
另一部分是类型指针,用于JVM确认对象所属类实例。

对象创建

JVM执行new指令时,会区常量池定位这个类的符号引用,检查这个符号引用代表的类是否已经被加载、解析、初始化过,没有则进行类加载。
为新对象分配内存的方式大致分为两种:
  • 堆为对象分配内存的方式
    • “指针碰撞”——假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一 边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那 个指针向空闲空间方向挪动一段与对象大小相等的距离。
    • 空闲列表——假设Java堆中的内存并不是规整的,已被使用的内存和空闲的内存相互交错在一起,那 就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分 配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。
JVM选择哪种依据其垃圾收集器决定。
内存分配(更新操作)的原子性原理
划分空间时,在并发情况下可能是不安全的。例如对象A与对象B同时使用指针分配内存。
JVM默认采用CAS(Compare And Swap)搭配失败重试的方式保证操作的原子性。

对象访问

HotSpot主要使用直接指针访问对象。

内存泄漏分析(生产)

JVM配置参数-XX:+HeapDumpOnOutOfMemoryError 可以让虚拟机在出现内存溢出异常的时候Dump当前内存堆转储快照。
也可以使用JMap命令导出Dump。
然后使用mat工具进行分析,如下:

大对象

占用较大连续内存空间的对象,一般是大数组、包含大量字段或嵌套对象的对象(复杂对象结构)、大型字符串对象。
将大对象直接分配到老年代可以避免“占用新生代内存导致提前GC带来的性能损耗”、“大对象在垃圾回收时的复制带来的性能损耗”,是一种JVM优化策略。
值得注意的是,JDK8默认收集器是Parallel Scavenge与Parallel Old,大对象不会直接放到老年代。会照常进行回收流程。
JVM在配置使用Serial和parNew两款收集器时,可以通过参数-XX:PretenureSizeThreshold来设定一个阈值,如果对象的大小超过阈值会被视为“大对象”,并被直接分配到老年代。
对于G1收集器,其引入了“HUmongous对象”的概念,任何超过Region大小一半的对象都会被视为巨型对象直接分配到老年代。

大对象的影响

  • 内存分配:大对象可能需要分配较大的连续内存块,这可能导致堆内存碎片化问题。
  • 垃圾回收:某些垃圾回收器(如 G1 GC)对大对象有特殊处理机制,可能会直接分配到老年代(而不是新生代)。

解决

在日常编码中要尽量避免大对象,不可避免时尽量复用,如使用对象池。
对于大数组对象,进行分割、将其分割为小对象进行操作。
或者使用手动释放的堆外内存。
 

try {

        ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024);

        // 使用 buffer

} finally {

        if (buffer != null && buffer.isDirect()) {

                ((sun.misc.Cleaner) sun.misc.Unsafe.getUnsafe().invokeCleaner(buffer)).clean();

        }

}

相关文章:

[java基础-JVM篇]1_JVM自动内存管理

JVM内存管理涉及但不限于类加载、对象分配、垃圾回收等,本篇主要记录运行时数据区域与对象相关内容。 内容主要来源《深入理解Java虚拟机:JVM高级特性与最佳实践》与官方文档,理解与表述错漏之处恳请各位大佬指正。 目录 运行时数据区域 栈 栈…...

安宝特科技 | Vuzix Z100智能眼镜+AugmentOS:重新定义AI可穿戴设备的未来——从操作系统到硬件生态,如何掀起无感智能革命?

一、AugmentOS:AI可穿戴的“操作系统革命” 2025年2月3日,Vuzix与AI人机交互团队Mentra联合推出的AugmentOS,被业内视为智能眼镜领域的“iOS时刻”。这款全球首个专为智能眼镜设计的通用操作系统,通过三大突破重新定义了AI可穿戴…...

Unity FBXExport导出的FBX无法在Blender打开

将FBX转换为obj: Convert 3D models online - free and secure...

UE5销毁Actor,移动Actor,简单的空气墙的制作

1.销毁Actor 1.Actor中存在Destory()函数和Destoryed()函数 Destory()函数是成员函数,它会立即标记 Actor 为销毁状态,并且会从场景中移除该 Actor。它会触发生命周期中的销毁过程,调用 Destroy() 后,Actor 立即进入销毁过程。具体…...

【python】提取word\pdf格式内容到txt文件

一、使用pdfminer提取 import os import re from pdfminer.high_level import extract_text import docx2txt import jiebadef read_pdf(file_path):"""读取 PDF 文件内容:param file_path: PDF 文件路径:return: 文件内容文本"""try:text ext…...

002简单MaterialApp主题和Scaffold脚手架

002最简单的MaterialApp主题和Scaffold脚手架使用导航栏_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1RZ421p7BL?spm_id_from333.788.videopod.episodes&vd_source68aea1c1d33b45ca3285a52d4ef7365f&p1501.MaterialApp纯净的 /*MaterialApp 是主题,自带方向设…...

jdk21下载、安装(Windows、Linux、macOS)

Windows 系统 1. 下载安装 访问 Oracle 官方 JDK 下载页面 或 OpenJDK 下载页面,根据自己的系统选择合适的 Windows 版本进行下载(通常选择 .msi 安装包)。 2. 配置环境变量 右键点击 “此电脑”,选择 “属性”。 在左侧导航栏…...

Baklib知识中台引领服务智能化

智能中枢系统架构解析 Baklib 知识中台的智能中枢系统采用分层解耦设计,通过数据接入层、知识处理层与服务输出层的三级架构实现全链路智能化管理。在数据接入层,系统支持多源异构数据的实时采集与标准化清洗,涵盖结构化数据(如客…...

Spring源码分析の循环依赖

文章目录 前言一、循环依赖问题二、循环依赖的解决三、整体流程分析 前言 常见的可能存在循环依赖的情况如下: 两个bean中互相持有对方作为自己的属性。   类似于: 两个bean中互相持有对方作为自己的属性,且在构造时就需要传入&#xff1a…...

检查SSH安全配置-关于“MaxStartups参数”

官方文档介绍 在《检查SSH安全配置-sshd服务端未认证连接最大并发量配置》中我们简略地阐述了“MaxStartups参数”在SSH安全配置中的意义。但是,并未对该参数做详细说明。 为啥没有详细说明呢?因为俺也没弄明白! 我们先看一下sshd_config的…...

某查”平台请求头反爬技术解析与应对

一、请求头反爬技术概述 请求头(HTTP Header)是 HTTP 协议中用于在客户端和服务器之间传递信息的一部分。它包含了请求的来源、用户代理、内容类型等关键信息。许多网站通过检查请求头中的特定字段来判断请求是否来自合法的浏览器,从而防止爬…...

MOE结构解读和deepseek的MoE结构

不管dense还是MoE(Mixture of Experts)都是基于transformer的。 下面回顾下解码器块的主要架构: 注意力机制-层归一化&残差连接-FFN前馈神经网络-层归一化&残差连接。 dense模型是沿用了这个一架构,将post-norm换为pre-no…...

LLM+多智能体协作:基于CrewAI与DeepSeek的邮件自动化实践

文章目录 引言理解 Flows(工作流)与 Crews(协作组)一、环境准备与工具安装1.1 Python环境搭建1.2 创建并激活虚拟环境1.3 安装核心依赖库(crewai、litellm) 二、本地DeepSeek R1大模型部署2.1 Ollama框架安…...

基于C++“简单且有效”的“数据库连接池”

前言 数据库连接池在开发中应该是很常用的一个组件,他可以很好的节省连接数据库的时间开销;本文基使用C实现了一个简单的数据库连接池,代码量只有400行只有,但是压力测试效果很好;欢迎收藏 关注,本人将会…...

为什么要将PDF转换为CSV?CSV是Excel吗?

在企业和数据管理的日常工作中,PDF文件和CSV文件承担着各自的任务。PDF通常用于传输和展示静态的文档,而CSV因其简洁、易操作的特性,广泛应用于数据存储和交换。如果需要从PDF中提取、分析或处理数据,转换为CSV格式可能是一个高效…...

Redis 集群的三种模式:一主一从、一主多从和多主多从

本文记述了博主在学习 Redis 在大型项目下的使用方式,包括如何设置Redis主从节点,应对突发状况如何处理。在了解了Redis的集群搭建和相关的主从复制以及哨兵模式的知识以后,进而想要了解 Redis 集群如何使用,如何正确使用&#xf…...

面试题——简述Vue 3的服务器端渲染(SSR)是如何工作的?

面试题——简述Vue3的服务器端渲染(SSR)是如何工作的? 服务器端渲染(SSR)已经成为了一个热门话题。Vue 3,作为一款流行的前端框架,也提供了强大的SSR支持。那么,Vue 3的SSR究竟是如…...

2.25DFS和BFS刷题

洛谷P1101单词方阵:用sta存字符串,for找到‘y的位置,然后dfs对字符串用for进行一个一个的判断,不符合就return,下面再用for进行book标记,能执行下面的for说明上面没有return,所以说明找到&#…...

C语言基本知识------指针(4)

1. 回调函数是什么? 回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数 时,被调⽤的函数就是回调函数。 void qsort(void base,//指针…...

【OMCI实践】ONT上线过程的omci消息(六)

引言 在前四篇文章中,主要介绍了ONT上线过程的OMCI交互的第一、二、三个阶段omci消息,本篇介绍第四个阶段,OLT下发配置到ONT。前三个阶段,每个厂商OLT和ONT都遵循相同标准,OMCI的交换过程大同小异。但第四个阶段&…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

基于服务器使用 apt 安装、配置 Nginx

🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...