JVM调优(一)
- 什么时候会有内存泄漏,怎么排查?
答:
首先内存泄漏是堆中的一些对象不会再被使用了,但是无法被垃圾收集器回收,如果不进行处理,最终会导致抛出 java.lang.OutOfMemoryError
异常。
内存泄露:
- 不需要使用的对象被其他对象不正确的引用,导致无法回收。
- 对象生命周期过长
内存泄漏的8中情况:
-
大量使用静态集合类(
HashMap、LinkedList
等),静态变量的生命周期和JVM程序一致,在程序结束之前,静态变量不会被释放,导致内存泄漏。(属于生命周期过长) -
单例模式的静态特性,也会导致生命周期过长,如果单例对象持有外部对象的引用,会导致外部对象不会被回收。
-
内部类持有外部类:每个非静态内部类都会持有外部类的隐式引用,假如
a
为非静态内部类,b
为a
的外部类,如果b
包含了大量对象的引用,非常占用内存空间,那么如果我们创建了非静态内部类a
,此时即使b
对象不再被使用了,也无法回收,占用内存空间,导致内存泄漏。解决办法:如果内部类不需要访问外部类的成员信息,可以考虑转换为静态内部类。
-
各种连接(数据库连接、网络连接和IO连接)未及时关闭,导致大量对象无法回收,造成内存泄漏。
-
变量不合理的作用域:一个变量的定义的作用范围大于其适用范围,很有可能造成内存泄露。
-
改变哈希值:
当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了。
否则,对象修改后的哈希值与最初存入HashSet集合时的哈希值就不同了,这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致HashSet集合中无法单独删除当前对象,造成内存泄漏
为什么改变哈希值之后找不到对象?因为根据存入时的哈希值去寻找放入的位置,而改变哈希值之后,再去查找就按照新的哈希值所对应的位置去查找,肯定找不到。
这也是 String 为什么被设置成了不可变类型,我们可以放心的把 String 存入 HashSet,或者把String当作 HashMap 的 key 值。
public class ChangeHashCodeTest {public static void main(String[] args) {HashSet<Point> set = new HashSet<>();Point cc = new Point();cc.setX(10); // hashCode = 10set.add(cc);cc.setX(20); // hashCode = 20System.out.println("set remove = " + set.remove(cc));set.add(cc);System.out.println("set.size = " + set.size());/*** 输出:* set remove = false* set.size = 2*/} } class Point {int x;public int getX() {return x;}public void setX(int x) {this.x = x;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Point point = (Point) o;return x == point.x;}@Override public int hashCode() {return x;} }
-
缓存泄露:
一旦把对象引用放入到缓存中,他就很容易遗忘。比如:之前项目在一次上线的时候,应用启动奇慢,就是因为代码会加载一个表的数据到缓存中,测试环境只有几百条数据,而生产环境有几百万的数据。
对于这个问题,可以使用WeakHashMap代表缓存,此Map的特点是:当除了自身有key的引用外,此key没有其他引用,那么此map会自动丢弃此值。
-
ThreadLocal
ThreadLocal的实现中,每个Thread维护一个ThreadLocalMap映射表,key是ThreadLocal实例本身,value是真正需要存储的Object。
ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用来引用它,那么系统GC时,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value。
如果当前线程迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。
如何解决此问题?
第一,使用ThreadLocal提供的remove方法,可对当前线程中的value值进行移除;
第二,不要使用ThreadLocal.set(null) 的方式清除value,它实际上并没有清除值,而是查找与当前线程关联的Map并将键值对分别设置为当前线程和null。
第三,最好将ThreadLocal视为需要在finally块中关闭的资源,以确保即使在发生异常的情况下也始终关闭该资源。
try {threadLocal.set(System.nanoTime()); } finally {threadLocal.remove(); }
排查内存泄漏:
可以查看泄露对象
到GC Roots
的引用链,找到泄露对象在哪里被引用导致无法被回收
- JVM常见配置
堆设置
-Xms3550m 初始堆大小
-Xmx3550m 最大堆大小
-XX:NewSize=1024 设置年轻代大小
-XX:NewRatio=4 设置年轻代和年老代的比值.如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=8 设置年轻代中Eden区与一个Survivor区的比值,默认为8
-XX:MaxPermSize=256m 设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数.并行收集线程数.
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比.公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式.适用于单CPU情况.
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数.并行收集线程数.
- JVM的堆配置过大的副作用有哪些?
答:JVM的堆内存配置过大,可能要面临的问题有:
- 回收大块堆内存而导致的长时间的时间停顿。
- 如果因为程序设计失误,将大对象从磁盘读取到内存中,可能会导致大对象在分配时直接进入老年代,没有在 Minor GC 中被清理掉。这样会导致频繁的发生 Full GC,给用户的体验是程序每个几分钟就停顿十几秒,非常卡顿。
扩展:JVM的堆配置过小的副作用有哪些?
- Minor GC 过于频繁
- 如果出现堆内存溢出
java.lang.OutOfMemoryError Java heap space
,该如何解决?
答:解决思路如下:
- 首先需要拿到
堆转储快照
进行分析,查看导致 OOM 的对象是否有必要存在,并且分析清除是因为哪些对象导致了 OOM - 如果是内存泄漏导致 OOM,可以查看
泄露对象
到GC Roots
的引用链,找到泄露对象在哪里被引用导致无法被回收 - 如果不是内存泄漏,那么说明内存中的对象都是存活的,导致 OOM,这时应该检查虚拟机的堆内存设置是否有向上调整的空间。并且检查是否存在
对象生命周期过长
、存储结构不合理
的情况,减少程序运行中的内存消耗。
扩展说明:因为存储结构不合理导致堆内存溢出(来自于《深入理解Java虚拟机第3版》)
举例:使用 HashMap<Long, Long>
存储大量的数据,会导致浪费大量的空间,因为 HashMap 的空间效率使用太低。
对于一个 HashMap<Long, Long>
来说,有效数据只有 Key、Value 的两个 long 型数据,占 16字节,long 数据被包装为 java.lang.Long 对象后,就分别具有 8 字节的 Mark Word、8字节的 Klass 指针、8字节的 long 型数值。两个 Long 对象组成 Map.Entry 之后,又多了 16 字节的对象头、8字节的 next 字段、4字节的 int 型的 hash 字段、4字节的空白填充(为了对齐)还有 HashMap 中对这个 Entry 的 8 字节的引用,这样实际占用的内存为:(Long(24byte) * 2) + Entry(32byte) + HashMap Ref(8byte)=88byte
,空间效率仅仅为 16byte / 88byte = 18%。
- 写代码时候有没有什么方式尽量减少Full GC的概率?
答:
- 避免一次性加载大量数据加载到内存,比如excel导入导出,jdbc数据库查询
- 避免大对象的代码处理业务链流程过长,比如aop中获取到了对象参数,大对象捕获到了,导致对象生命周期变长了,没及时释放。
- 禁止使用system.gc方法
- 避免在使用threalocal后,未主动调用remove方法,尽量避免大对象的使用,以及频繁的创建和销毁。更要避免全局锁的竞争等。
相关文章:
JVM调优(一)
什么时候会有内存泄漏,怎么排查? 答: 首先内存泄漏是堆中的一些对象不会再被使用了,但是无法被垃圾收集器回收,如果不进行处理,最终会导致抛出 java.lang.OutOfMemoryError 异常。 内存泄露: …...

Parallels Desktop 19中文-- PD19最新安装
Parallels Desktop 19可以让我们在Mac电脑上运行Windows和其他操作系统,而无需重启计算机。这款软件的稳定性较高,能够在Mac上同时运行多个操作系统,如Windows、Linux等,而无需重启电脑。它可以让用户无缝地在不同操作系统之间切换…...
【c++】向webrtc学比较1:AheadOf、IsNewerTimestamp
webrtc源码分析-rtp序列号新旧比较 大神文章分析的非常到位。大神分析:AheadOrAt(a, b)是判断a是否比b新的核心,其原理是这样的:rfc1982规定了序列号递增间隔不能超过取值范围的1/2(这是自己理解的),那么要判断a是否比b新,只要判断b到a的递增是否在1/2即可,递增超过1/2,…...

华为云云耀云服务器L实例评测|企业项目最佳实践之docker部署及应用(七)
华为云云耀云服务器L实例评测|企业项目最佳实践系列: 华为云云耀云服务器L实例评测|企业项目最佳实践之云服务器介绍(一) 华为云云耀云服务器L实例评测|企业项目最佳实践之华为云介绍(二) 华为云云耀云服务器L实例评测࿵…...

MAC上使用Wireshark常见问题
文章目录 介绍正文启动异常-Permission denied解决方法 过滤协议和地址指定源地址和目的地址调整 time format 介绍 简单记录Wireshark在日常使用过程中的遇到的小case。 正文 Wireshark相较于tcpdump使用较为简单,交互也更为友好。 点击Start即可启动抓包 启动…...
在C++中++a和a++有什么区别?
2023年10月16日,周一中午 a和a在语义上的区别 a是先进行运算(增加1),然后返回新值。 a是先返回原值,然后进行运算(增加1)。 a和a在效率上的区别 a直接返回新值,不需要临时变量保存原值。 而a需要先返回原值,然后再进行增加1的操作。这需要使用一个临时变量来保存…...

NewStarCTF2023公开赛道-压缩包们
题目提示是压缩包 用010editor打开,不见PK头,补上50 4B 03 04 14 00 00 00 将文件改成.zip后缀,打开,解压出flag.zip 尝试解压,报错 发现一串base64编码 SSBsaWtlIHNpeC1kaWdpdCBudW1iZXJzIGJlY2F1c2UgdGhleSBhcmUgd…...
oracle数据库增加表空间数据文件
查询数据文件:select * from dba_data_files order by file_name; 增加:alter tablespace 数据库名 add datafile data size 34359721984;...
【08】基础知识:React中收集表单数据(非受控组件和受控组件)
一、概念 非受控组件: 页面中所有输入类的 DOM,现用现取。 给组件绑定 ref 属性,在需要时通过 ref 获取相应值。 受控组件: 页面中所有输入类的 DOM,随着输入,将内容维护到状态 state中,当…...

数据结构之堆排序和前,中,后,层序遍历,链式二叉树
首先我们要知道升序我们要建小堆,降序建大堆,这与我们的大多人直觉相违背。 因为我们大多数人认为应该将堆顶的数据输出,但如果这样就会导致堆顶出堆以后,堆结构会被破坏,显然我们不能这样。 所有我们反其道而行&…...

多线程中ThreadPoolExecutor.map()中传递多个参数
with concurrent.futures.ThreadPoolExecutor(max_threads) as executor:results executor.map(get_captcha_image, ip_addrs, [img_url] * len(ip_addrs)) #要传入多个参数时,每个参数都得是固定相同长度的可迭代对象# 收集结果for result in results:print(resul…...

linux centos7 环境下 no such file or directory
目录 1.问题描述2.主要原因2.1修改后代码2.2修改前代码 总结参考 1.问题描述 预览excel文件时无法找到对应的html文件 2.主要原因 异常原因:代码获取的是系统的tmp文件,但是linux环境环境中心tmp目录是没有权限的,所以不能获取系统的根目录…...
Nginx 反向代理 SSL 证书绑定域名
配置 Nginx 反向代理和 SSL 泛域名证书绑定域名 Nginx 是一个功能强大的 Web 服务器和反向代理服务器,可以用于将客户端请求转发到后端服务器,并提供安全的 HTTPS 连接。本文将介绍如何配置 Nginx 反向代理,并使用 SSL 泛域名证书绑定域名&a…...
SpringBoot 集成 JMS 与 IBMMQ 代码示例教程
文章目录 前言一、集成 JMS 与 IBMMQ1、pom 依赖2、yml 配置3、Properties 配置类4、Factory 连接工厂类5、配置连接认证6、配置缓存连接工厂7、配置事务管理器8、配置JMS模板9、消息发送与接收 总结 前言 SpringBoot 集成 IBMMQ,实现两个服务间的消息通信。 一、集…...

大模型之Prompt研究和技巧
大模型之Prompt研究和技巧 大模型之Prompt编写简介组成技术Zero-ShotFew-shotCOTCOT-SCTOTGoTReAct 大模型之Prompt编写 简介 Prompt是是给 AI **模型的指令,**一个简短的文本输入,用于引导AI模型生成特定的回答或执行特定任务。 Prompt是你与语言模型沟…...

掌握Golang匿名函数
一个全面的指南,以理解和使用Golang中的匿名函数 Golang以其简单和高效而闻名,赋予开发人员各种编程范式。其中一项增强代码模块化和灵活性的功能就是匿名函数。在这篇正式的博客文章中,我们将踏上探索Golang匿名函数深度的旅程。通过真实世…...
HarmonyOS云开发基础认证---练习题二
【判断题】 2/2 Serverless是云计算下一代的默认计算范式。 正确(True) 【判断题】 2/2 接入认证服务后,用户每次收到验证码短信都需要开发者买单。 错误(False) 【判断题】 2/2 认证服务手机号码登录需要填写国家码。 正确(True) 【判断题】 2/2 在Cloud Functi…...
ffmpeg视频解码器的配置选项含义
lowres的含义 lowres是AVCodecContext结构体中的一个成员变量,用于指定编解码器的降低分辨率级别。 在某些情况下,为了加快编解码的速度或减少计算资源的消耗,可以通过设置lowres参数来降低编解码器的分辨率级别。这将导致编解码器在处理视…...
enter ubuntu boot option in virt-manager
在全屏模型下,启动过程中按下F8或者Ctrl F8。 参考:https://serverfault.com/questions/463024/how-do-i-access-the-f8-bootmenu-while-booting-a-windows-2008r2-kvm-guest-vm...
电商运营该如何做 AB 测试
更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 近年,电商行业进入了一个新的发展阶段,一方面电商市场规模持续扩大,另一方面直播电商、即时零售、社区团购等新兴电商业态在疫情…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...