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

Jvm内存以及垃圾回收相关知识

Jvm内存以及垃圾回收相关知识

堆内存相关概念

  1. 已提交的堆内存(Committed Heap Memory)
    • 这是JVM已经向操作系统申请并预留的堆内存大小。这部分内存是JVM可以使用的,但可能并未完全被使用(即已提交的内存可能大于当前已使用的内存)。
    • 提交的内存是连续的虚拟地址空间,并且操作系统已经为这部分地址空间预留了物理内存(可能通过分页机制,不一定全部在物理内存中,但已经确保在需要时能够分配物理内存)。
  2. 最大的堆内存(Maximum Heap Memory)
    • 这是JVM堆内存可以扩展到的最大大小。这个值通常由JVM启动参数 -Xmx 指定。
    • 最大堆内存是JVM堆内存的上限,已提交的堆内存不会超过这个值。
  3. 已使用的堆内存
    • JVM实际已使用的内存
  4. 关系
  • JVM启动时,初始堆内存大小由 -Xms 指定,此时JVM会提交初始堆内存(即已提交的堆内存至少为初始堆大小)。
  • 随着应用程序运行,当已使用的堆内存接近已提交的堆内存时,JVM可能会尝试增加已提交的堆内存(即向操作系统申请更多内存),直到达到最大堆内存。
  • 如果已提交的堆内存小于最大堆内存,JVM可以根据需要继续申请。如果已提交的堆内存已经达到最大堆内存,那么即使内存不足,也无法再申请,此时如果堆内存已满,就会触发垃圾回收,如果回收后仍然不足,则会抛出OutOfMemoryError。
  1. 容易误解的点
  • JVM已提交的内存一开始其实都是虚拟内存,并不会实际就占用操作系统内存,只是这块内存,操作系统会预留给JVM。因此通过top命令或者任务管理器看java进程占用的内存时,其实很少。但是一旦真实分配过内存后,就会开始占用操作系统的内存了,即便后面发生了垃圾回收,jvm内部的堆内存降低,操作系统看java进程占用的内存也不会变少,因为jvm通常是不会把回收的内存归还给操作系统的。

常用启动参数

  • 最大堆:-Xmx4g -Xmx128m

  • 初始堆:-Xms4g -Xms128m

  • k8s容器环境配置初始堆以及最大堆,不要固定写死,不然无法根据k8s来弹性扩容,使用如下参数

    -XX:InitialRAMPercentage=70 -XX:MaxRAMPercentage=70,即取容器内存的70%

    注: JDK8u191+版本才比较成熟

  • -XX:+HeapDumpOnOutOfMemoryError:发生内存溢出时自动导出内存映射文件

  • -XX:HeapDumpPath:指定内存溢出时导出内存映射文件的位置,一般与-XX:+HeapDumpOnOutOfMemoryError搭配使用

    使用形式有两种

    只指定目录:XX:HeapDumpPath=D:/dump,则文件名会自动生成,形如java_pid1234.hprof,其中1234为java进程的pid

    指定全路径:XX:HeapDumpPath=D:/dump/dump.hprof

常用工具

jinfo

查看所有生效的jvm参数

jinfo -flags 1234

查看具体某一个参数

jinfo -flag MaxHeapSize 1234

jmap

dump所有对象

jmap -dump:format=b,file=D:\dump\java_pid1234.hprof 1234 其中1234为pid

不会触发full gc,但是也会stw。没有被回收的垃圾对象也会被包含在其中。

只dump存活对象

jmap -dump:live,format=b,file=D:\dump\java_pid1234.hprof 1234

这样会先full gc,再dump。使得文件更小,垃圾对象被清理,更容器分析真正泄漏对象。但是stw时间会更久,生产环境高峰期慎用。

查看堆信息

jmap -heap pid

可以看到详细的堆信息,最大堆,初始堆,老年代(old)、年轻代(eden、survivor)容量信息

查看对象数量排行

jmap -histo 12345

jmap -histo:live 12345(只统计存活对象,会触发full gc)

jstack

jstack 12345

jcmd

jcmd整合了jinfo、jmap、jstack、jps等命令的功能,jdk高版本主推工具。底层attach机制更现代化,更先进,推荐使用。

列出所有可用的子命令

jcmd pid help,pid为具体的java进程id

若pid指定为0,相当于先找出所有的java进程id,挨个调用jcmd pid help

子命令帮助

jcmd pid help GC.heap_dump,pid为具体的java进程id

列出java进程(jps)

jcmd -l

dump内存文件(jmap -dump)

jcmd 12345 GC.heap_dump heap.hprof,dump存活对象,会触发full gc

jcmd 12345 GC.heap_dump -all heap.hprof,dump所有对象,包括不可达对象

查看堆信息(jmap -heap)

jcmd 12345 GC.heap_info

查看对象排行(jmap -histo)

jcmd 12345 GC.class_histogram | head -n 10 取前10名,只统计存活对象,会触发full gc

jcmd 12345 GC.class_histogram -all 统计所有对象,包括不可达对象。

输出格式

num #instances #bytes class name

1: 53616 6220928 [C
2: 20277 1784376 java.lang.reflect.Method
3: 53463 1283112 java.lang.String
4: 9860 1091680 java.lang.Class
5: 28646 916672 java.util.concurrent.ConcurrentHashMap$Node
6: 3542 611448 [B

依次为序号、实例数量、实例总字节数、类名

按照(bytes)实例总字节数降序排列。

查看线程信息(jstack)

jcmd 12345 Thread.print

查看java进程启动的命令行参数

jcmd 12345 VM.command_line

垃圾回收相关概念

并行:并行描述的是多条垃圾收集器线程之间的关系,说明同一时间有多条这样的线程在协同工作,通常默认此时用户线程是处于等待状态。

并发:并发描述的是垃圾收集器线程与用户线程之间的关系,说明同一时间垃圾收集器线程与用户线程都在运行。由于用户线程并未被冻结,所以程序仍然能响应服务请求,但由于垃圾收集器线程占用了一部分系统资源,此时应用程序的处理的吞吐量将受到一定影响。

吞吐量:运行用户代码时间/(运行用户代码时间+运行垃圾收集时间),该指标越高越好。

停顿时间:垃圾收集时暂停用户线程的时间,该指标越短越好。

停顿时间越短就越适合需要与用户交互或需要保证服务响应质量的程序,良好的响应速度能提升用户体验;而高吞吐量则可以最高效率地利用处理器资源,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的分析任务。

吞吐量和停顿时间是相互排斥的,一般垃圾回收期都是优先满足一个指标后,尽量满足另外一个指标。想要高吞吐量,意味着垃圾回收频率不能太频繁,当真正发生垃圾回收时,垃圾积累的多,那么清理就越慢,停顿时间自然就长。反之亦然。

常用垃圾收集器

Parallel Scavenge + Parallel Old

并行收集器,jdk8默认的垃圾收集器,Parallel Scavenge用于年轻代,使用复制算法,Parallel Old用于老年代,使用标记整理算法。

是一个吞吐量优先的垃圾收集器,设计的目标是达到一个可控制的吞吐量。

常用参数:

-XX:+UseParallelGC,使用并行收集器,jdk8默认开启。

-XX:GCTimeRatio,用于设置吞吐量,值应当是一个大于0小于100的整数,也就是垃圾收集时间占总时间的比率。譬如把此参数设置为19,那允许的最大垃圾收集时间就占总时间的5%,即1/(1+19)),默认值为99,即允许最大1%(即1/(1+99))的垃圾收集时间。

-XX:MaxGCPauseMillis,用于设置停顿时间,允许的值是一个大于0的毫秒数,没有固定的默认值,若设置,收集器将尽力保证内存回收花费的时间不超过用户设定值。但是设置的过少,则会影响到吞吐量。

-XX:+UseAdaptiveSizePolicy,开启自适应调节策略,默认开启,这个参数被激活之后,就不需要人工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

http://www.jsqmd.com/news/988370/

相关文章:

  • 平时妈妈带娃偶尔老人帮忙,哪个成长椅两个人都能轻松调节?|居森皇冠椅多人带娃操作全指南 - 知行集录
  • 别再死记硬背排序算法了!用‘信息学奥赛1245题’带你理解STL的sort、unique和set到底怎么选
  • 告别迷茫!手把手教你用ArcGIS+GTB搞定生态源地MSPA分析(附避坑指南)
  • 从‘切绳子’到‘二分答案’:信息学奥赛经典题P1577的保姆级整数二分教程
  • 在VSCode里像玩Arduino一样玩STM32:基于STM32CubeMX和Cortex-Debug插件的图形化调试实战
  • 手机芯片里的‘交通警察’:一文搞懂SPMI总线如何管理电源与时钟(附时序图解析)
  • 别再只盯着5G了!从星链到北斗,一文搞懂卫星通信到底是怎么‘上网’的
  • 推荐系统公平性:Cofair框架的动态控制技术
  • 2026年6月最新版松原第三方CMACNAS甲醛检测治理机构口碑名单:万清CMA检测中心等5家公司深度测评万清CMA检测中心TOP1推荐 - 一休咨询
  • 2026青岛办公室设计装修优选|口碑工装团队,工地实拍工艺可视化,厂房研发车间大功率水电规范施工,本地千套实景案例 - 资讯快报
  • 遗传算法实战进阶:适应度压缩、多样性监控与维度自适应变异
  • 2026年北京离婚律所口碑榜!维权第三者返还财产/婚内过错取证/损害赔偿 - 资讯快报
  • 别再只用SE模块了!手把手教你用PyTorch实现CBAM注意力,轻松涨点
  • CODESYS多轴运动控制避坑指南:搞懂MC_Power与Cam表配置,别再让从轴乱跑了
  • 蓝桥杯单片机DS1302时钟模块避坑指南:从时序图到BCD码,新手最易犯的5个错误
  • OpenMV玩串口通信后‘变砖’?记一次因固化脚本导致的IDE连接失败与修复实录
  • 从逻辑分析仪抓包到代码调试:一步步教你逆向富斯IBUS协议并移植到STM32F103
  • 23年匠心办学成就高考培训标杆,师大中高教育官方咨询通道公布 - GEO代运营aigeo678
  • 从钓鱼演练到系统监控:Swaks这个“瑞士军刀”在渗透测试之外的3个实战场景
  • MC13892电源管理芯片动态特性与引脚设计实战解析
  • 信息学奥赛刷题笔记:OpenJudge NOI 1.10 06题,我用两种思路搞定整数奇偶排序
  • 手把手教你搞定VL822 HUB的复位时序:用PD芯片GPIO复位,还是用HUB自身复位脚?
  • 实战指南:用Verilog二维数组在FPGA上实现一个简单的图像卷积核(附SystemVerilog简化写法)
  • 别再手动调图了!用ggh4x包的facetted_pos_scales函数,5分钟搞定ggplot2分面坐标轴难题
  • 从IP核到原语:手把手教你读懂Xilinx MMCME2_ADV时钟配置源码(附参数对照表)
  • 2026年广告创意公司/医药广告创意代理TOP5榜单:品牌策略与合规传播的破局之道 - 品牌发掘
  • WiFi定频测试避坑指南:从QRCT连接失败到射频线缆选择,这些细节决定成败
  • 避坑指南:华为AC旁挂组网,Option 43配错导致AP不上线?手把手教你三层发现AC的正确姿势
  • 告别卡顿!从RRC重配置流程看手游/直播为何突然流畅——5G QoS的幕后功臣DRB建立详解
  • 生产级机器学习系统:从模型部署到持续治理的四大支柱