当前位置: 首页 > 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.gsyq.cn/news/1500119.html

相关文章:

  • 平时妈妈带娃偶尔老人帮忙,哪个成长椅两个人都能轻松调节?|居森皇冠椅多人带娃操作全指南 - 知行集录
  • 告别迷茫!手把手教你用ArcGIS+GTB搞定生态源地MSPA分析(附避坑指南)
  • 手机芯片里的‘交通警察’:一文搞懂SPMI总线如何管理电源与时钟(附时序图解析)
  • 别再只用SE模块了!手把手教你用PyTorch实现CBAM注意力,轻松涨点
  • OpenMV玩串口通信后‘变砖’?记一次因固化脚本导致的IDE连接失败与修复实录
  • 从逻辑分析仪抓包到代码调试:一步步教你逆向富斯IBUS协议并移植到STM32F103
  • MC13892电源管理芯片动态特性与引脚设计实战解析
  • 避坑指南:华为AC旁挂组网,Option 43配错导致AP不上线?手把手教你三层发现AC的正确姿势
  • 2026年广告创意公司/医药广告创意代理TOP5榜单:品牌策略与合规传播的破局之道 - 品牌发掘
  • 告别卡顿!从RRC重配置流程看手游/直播为何突然流畅——5G QoS的幕后功臣DRB建立详解
  • Altium Designer 19 自定义库管理实战:解决‘画了找不到’和工具栏消失问题
  • 2026年6月最新版苏州第三方CMACNAS甲醛检测治理机构口碑名单:万清CMA检测中心等5家公司深度测评万清CMA检测中心TOP1推荐 - 一休咨询
  • CloudCompare点云高程归一化保姆级教程:从CSF到泊松重建,四种方法实测对比与避坑指南
  • Python 爬虫项目 Cookie 池搭建与会话隔离实战
  • mysql应用层分表(Application-Level Sharding)知识笔记
  • 多维聚合实战:ROLLUP、CUBE与GROUPING SETS原理与优化
  • 多维聚合中的数据操纵:从OLAP立方体到CEO驾驶舱的四层解剖
  • 从OpenJudge一道题出发,聊聊C++里处理字符串输入的那些“坑”与技巧
  • 不止是列表:用RimWorld的Def系统设计你的第一个原创事件(IncidentDef实战)
  • 告别AP直连:用华为AC+交换机搭建可扩展的无线办公网(隧道转发详解)
  • ggplot2分面进阶:用ggh4x包的facetted_pos_scales函数优雅定制每个面板的坐标轴
  • 别再只会用插值了!用PyTorch的PixelShuffle层实现更自然的图像超分辨率
  • 上海企业搬迁公司推荐:主流厂商对比参考 - 资讯快报
  • 2026年6月伺服冲床企业选哪家,25吨伺服模切冲床/片材伺服模切冲床/小吨位伺服冲床,伺服冲床厂家哪家权威 - 品牌推荐师
  • 2026年条码扫描器经销商/厂家推荐榜:斑马、摩托罗拉、霍尼韦尔、新大陆等品牌手持/无线/工业扫描器深度测评与选购指南 - 品牌发掘
  • 生产级多维聚合:从Pandas groupby到业务语义建模
  • 用Presto时间函数搞定业务报表:周环比、月同比、季度初计算实战
  • 余弦相似度在客户流失预测中的可解释性应用
  • 手把手教你用思博伦GSS7000的SimReplayPlus模块:从开机到跑通第一个静态场景
  • 你的jQuery项目安全吗?一份针对CVE-2020-11022/23的升级与修复自查清单