JVM性能优化一:初识内存泄露-内存溢出-垃圾回收

本文主要是让你充分的认识到什么叫做内存泄露,什么叫做内存溢出,别再傻傻分不清了,别再动不动的升级服务器的内存了。

文章目录

    • 1.基本概念
      • 1.1.内存泄露
      • 1.2.内存溢出
      • 1.3.垃圾回收
      • 1.4.内存泄露-垃圾回收-内存溢出三者的关系关系
    • 2.代码示例
      • 2.1.示例1:模拟逐渐占用内存-释放内存
      • 2.2.示例2:模拟逐渐占用内存-不释放内存(内存泄露)
      • 2.3.示例3:模拟逐渐占用内存-释放内存(内存溢出)

1.基本概念

1.1.内存泄露

内存泄漏是指程序申请了内存后,不再使用某些内存空间,但未能正确释放,导致这部分内存无法被再次利用。虽然系统可能还有足够的内存供其他操作使用,但长期累积会逐渐耗尽可用内存,最终可能导致内存溢出。

1.2.内存溢出

当应用程序请求的内存超出了 JVM 分配的最大堆内存时,出现OOM异常

1.3.垃圾回收

当应用程序释放占用内存以后,JVM会按照自己的策略对已经释放的内存进行回收。并不是说程序执行结束,立马就进行内存回收,而是会在适当的时机进行回收。这意味着即使方法执行结束,内存的释放也可能会延迟,直到 JVM 认为有必要进行垃圾回收。

1.4.内存泄露-垃圾回收-内存溢出三者的关系关系

当存在内存溢出后,会导致内存逐渐被占用,而此时垃圾回收机制无法对这些占用的内存进行回收,由于内存不会被释放,导致可使用内存越来越少。如果最后内存无法满足接下来或者正在运行的代码所需要的内存,就会发生内存溢出。总结就是下面三条

  1. 内存泄露:逐步吞噬内存
  2. 垃圾回收:无法回收内存
  3. 内存溢出:内存不够分配

2.代码示例

以下代码,并未设置相关JVM参数,全是默认,每个人的JDK,内存都不一样,有人内存8G、16G、32G都有可能,因此可以视情况调整下面的循环次数,这里我是循环3000 * 10000次

2.1.示例1:模拟逐渐占用内存-释放内存

以下代码,就是一个很常见的,需求大概就是创建很多对象,然后把这个对象添加到集合中。为了演示效果,中间加了暂停效果,Thread.sleep。

/*** @description:内存泄露demo* @author:hutao* @throws InterruptedException * @mail:hutao1@epri.sgcc.com.cn*/
@GetMapping("/memory/leak")
public String leak() throws InterruptedException {log.info("开始调用/memory/leak");List<UserVO> list = new ArrayList<>();for (int i = 0; i < 3000 * 10000; i++) {if(i % (300 * 10000) == 0) {Thread.sleep(500);}UserVO temp = new UserVO();temp.setUserId("ID_"+ i);temp.setUserName("胡涛_" + i);temp.setUserAge(i);list.add(temp);}log.info("结束调用/memory/leak");return "leakTest";
}

启动我们的java程序以后,等待一段时间波动以后,观察到内存的占用率此时呈现一条水平线
在这里插入图片描述
接着通过浏览器调用我们上面的接口,在观察内存使用率,可以发现大概使用了5个G的内存,也就是说,该接口在被调用的时候,居然就使用了5个G的内存。
http://127.0.0.1:8080/demo1/memory/leak
在这里插入图片描述
然后持续观察一段时间以后,我们不难发现,好像内存没有释放哎?等了好久也没等到内存释放。怎么回事?这个代码是不是存在内存泄露的问题?
在这里插入图片描述
这时候别着急,思考一下,如果你没理解咱们上面说的基本概念,你大概会想
第一次调用就占用了5个G,第二次调用不就占用5个G了,第三次调用就内存溢出了。然后当你连续几次调用的时候,你就会发现,咦,咋回事?怎么没有继续占用内存啊,怎么内存呈现波浪形,一会占用,一会释放了。上面代码为啥没有出现我们最终设想内存溢出?到底为啥?
在这里插入图片描述
这时候你在看这句话是不是理解了?

1.内存泄露:逐步吞噬内存
2.垃圾回收:无法回收内存
3.内存溢出:内存不够分配

之所以没有出现内存溢出,为啥?因为垃圾回收机制,回收到了内存。然后内存被释放了。所以内存会介于被占用,被释放之间来回跳转。
这里提一句
假设你和我在代码中一样,想要方法结束调用以后,内存直接释放,写了如下这个代码

System.gc();

在这里插入图片描述
我的IDE提示我,当然提示语有点侮辱人,不要让我以为我比JVM还聪明,建议我删掉该代码,最主要的是,你发现没暖用,并没有出现程序执行完毕,立马释放内存的情况。

Don't try to be smarter than the JVM, remove this call to run the garbage collector.

2.2.示例2:模拟逐渐占用内存-不释放内存(内存泄露)

上面,我们模拟了会让JVM在他认为该回收垃圾的时候,去回收垃圾,然后释放内存,接下来,我们模拟一个JVM无法释放内存的例子,最红内存溢出OOM错误。
这里改动一下代码。仅需要两行代码,就能阻止垃圾回收机制释放内存,然后导致最后内存溢出。
添加一个cache的属性,并且该属性一直引用我们每次调用接口创建的list

private Map<String, List<UserVO>> cache = new HashMap<>();cache.put(UUID.randomUUID().toString(), list);

完整代码如下。思路就是把每次接口调用的数据都往cache里面存储。
你可以这样粗鲁的理解:list往cache里面不停的存放,最后导致cache越来越大,最后内存不够

你也可以这样正规的理解下:虽然方法中局部变量list不在使用,但是list被cache引用,而cache是demo1Controller(Spring创建的Controller对象) 对象的属性,demo1Controller一直被Spring引用,Spring一直在整个web引用程序中,因此cache相当于在整个web程序的生命周期都有效.

Spring 框架中,Controller 对象默认是单例的。
这意味着每个 Controller 类在 Spring 容器中只会有一个实例
所有的请求都会共享这个实例。
@RestController
@RequestMapping("/demo1")
@Log4j2
public class Demo1Controller {private Map<String, List<UserVO>> cache = new HashMap<>();/*** @description:内存泄露demo* @author:hutao* @throws InterruptedException * @mail:hutao1@epri.sgcc.com.cn*/@GetMapping("/memory/leak")public String leak() throws InterruptedException {log.info("开始调用/memory/leak");List<UserVO> list = new ArrayList<>();for (int i = 0; i < 3000 * 10000; i++) {if(i % (300 * 10000) == 0) {Thread.sleep(500);}UserVO temp = new UserVO();temp.setUserId("ID_"+ i);temp.setUserName("胡涛_" + i);temp.setUserAge(i);list.add(temp);}cache.put(UUID.randomUUID().toString(), list);log.info(cache.keySet());log.info("结束调用/memory/leak");return "leakTest";}
}

可以看到,如下所示,虽然没有出现内存一直持续暴涨的情况,但是如我们期待的那样,内存没有被释放,并且出现了OOM:Java heap space错误。如果你和我一样运行了代码,你可能会遇到,此时电脑特别卡,很卡。卡的要死。
在这里插入图片描述

2.3.示例3:模拟逐渐占用内存-释放内存(内存溢出)

在示例2中,我们不难发现,当我们第一次调用的时候,程序正常的,而程序在第二次调用的时候,内存并没有有释放,所以内存必然不够,因此第二次请求的时候,内存就不够分配了,因此导致内存溢出。

提示:虽然实际上还有接近5G物理内存,但是并不会把所有内存都分配给JVM这里的内存不够指,JVM分配到的内存不够

为了方便演示,这里我们开始引入JVM的一下参数说明

-Xms512m -Xmx1g-Xmx:设置 Java 堆的最大值。默认值通常为物理内存的四分之一。建议根据物理内存大小和其他内存开销来调整此值。
-Xms:设置 Java 堆的初始值。对于服务器端的 JVM,最好将此值与 -Xmx 设置为相同,以避免在运行时频繁调整内存。

在IDE启动中中,添加JVM参数,这里我设置,最大为1g
在这里插入图片描述
为了方便观察,这里我们记录一下内存使用情况

/*** @description:内存溢出demo* @author:hutao* @throws InterruptedException * @mail:hutao1@epri.sgcc.com.cn*/
@GetMapping("/memory/oom")
public String oom() throws InterruptedException {log.info("开始调用/memory/oom");log.info("最大可用内存:{}",Runtime.getRuntime().maxMemory());List<UserVO> list = new ArrayList<>();for (int i = 0; i < 3000 * 10000; i++) {if(i % (300 * 10000) == 0) {log.info("当前占用内存:{},当前空闲内存:{}", Runtime.getRuntime().totalMemory(),Runtime.getRuntime().freeMemory());Thread.sleep(500);}UserVO temp = new UserVO();temp.setUserId("ID_"+ i);temp.setUserName("胡涛_" + i);temp.setUserAge(i);list.add(temp);}log.info("结束调用/memory/oom");return "oomTest";
}

通过下面的截图,不难发现几个问题
1通过手动限制最大内存以后,第一次调用就内存溢出
2内存并没有像之前一样,直接占用了5g,而是按照我们分配的占用
3可以看到占用的内存逐渐增加,最终占满内存,无法给予程序所需要的内存
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64799.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dockfile镜像加速

运行给的终端命令 全覆盖法 {"registry-mirrors": ["https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://dockerhub.azk8s.cn","https://mirror.ccs.tencentyun.com","https://registry.cn-han…

数据结构经典算法总复习(下卷)

第五章:树和二叉树 先序遍历二叉树的非递归算法。 void PreOrderTraverse(BiTree T, void (*Visit)(TElemType)) {//表示用于查找的函数的指针Stack S; BiTree p T;InitStack(S);//S模拟工作栈while (p || !StackEmpty(S)) {//S为空且下一个结点为空&#xff0c;意味着结束遍…

Windows系统上创建Flask服务器

为什么需要掌握服务器搭建技能&#xff1f; 掌握服务器搭建技能对于任何需要在线提供服务或平台的个人创意者来说都至关重要。服务器的作用是确保全球任何地方的用户都能顺利访问你的平台。因此&#xff0c;了解如何搭建和维护服务器&#xff0c;不仅能提升平台的稳定性和访问…

ISP用到的一些名词简介

这里主要记录一下在学习ISP时遇到的一些名词。 图像质量(Picture Quality) 1.锐度&#xff08;Acutance&#xff09; 锐度常用于描述边界处图像信息过渡的快慢。高反差图像过渡速度非常快&#xff0c;可以形成非常明确的边缘&#xff0c;而低反差图像存在一定的过渡缓冲&#…

SqlSugar查询达梦数据库遇到的异常情况(续)

之前的文章提到在SqlSugar的Where函数中使用!string.IsNullOrEmpty函数查询达梦数据库时&#xff0c;明明数据库中有数据但就是查不出来&#xff0c;但相同的代码在另一台电脑上就可以正常返回数据。   以下图中的两张表数据为例&#xff0c;执行下面的SQL语句无法查询到数据…

Spark优化----Spark 性能调优

目录 常规性能调优 常规性能调优一&#xff1a;最优资源配置 常规性能调优二&#xff1a;RDD 优化 RDD 复用 RDD 持久化 RDD 尽可能早的 filter 操作 常规性能调优三&#xff1a;并行度调节 常规性能调优四&#xff1a;广播大变量 常规性能调优五&#xff1a;Kryo 序列化 常规性…

ECharts柱状图-柱图42,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个柱状图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供…

电商店铺数据集成到金蝶云星辰V2的实践经验分享

电商店铺数据集成到金蝶云星辰V2的技术案例分享 在电商业务快速发展的背景下&#xff0c;如何高效地将聚水潭平台上的电商店铺数据集成到金蝶云星辰V2系统中&#xff0c;成为了许多企业面临的重要挑战。本文将详细探讨一个实际运行的解决方案——“电商店铺->金蝶客户”&am…

(css)鼠标移入或点击改变背景图片

(css)鼠标移入或点击改变背景图片 html <div class"mapTip"><divv-for"(item, index) of legendList":key"index"class"mapTipOne":class"{ active: change index }"click"legendHandle(item, index)"…

Oracle virTualBox安装window10

一、下载windows10镜像 我下载的windows10镜像如下&#xff1a; 内部文件如下&#xff1a; 二、错误的安装方法 直接新建虚拟机&#xff0c;选择镜像文件&#xff1a; 启动虚拟机&#xff08;会一直提示没有启动设备&#xff0c;选择镜像后一直弹窗提示&#xff09; 三、正确…

四川托普信息技术职业学院教案1

四川托普信息技术职业学院教案 【计科系】 周次 第 1周&#xff0c;第1次课 备 注 章节名称 第1章 XML语言简介 引言 1.1 HTML与标记语言 1.2 XML的来源 1.3 XML的制定目标 1.4 XML概述 1.5 有了HTML了&#xff0c;为什么还要发展XML 1.5.1 HTML的缺点 1.5.2 XML的特点 1.6 X…

三维引擎cesium学习经验

三维引擎cesium学习经验&#xff1a; 1、初始化viewer对象 2、对entity的操作&#xff1a;添加&#xff0c;隐藏&#xff0c;修改&#xff0c;去除&#xff0c;居中显示 3、去除掉entity的双击事件 4、获取当前视角高度 5、获取经纬度在屏幕上的位置 6、获取三维场景屏幕中心点…

虚拟机VMware的安装问题ip错误,虚拟网卡

要么没有虚拟网卡、有网卡远程连不上等 一般出现在win11 家庭版 1、是否IP错误 ip addr 2、 重置虚拟网卡 3、查看是否有虚拟网卡 4、如果以上检查都解决不了问题 如果你之前有vmware 后来卸载了&#xff0c;又重新安装&#xff0c;一般都会有问题 卸载重装vmware: 第一…

裸机LED 灯实验

G1、硬件原理分析 2、寄存器说明 a、主要配置寄存器 使能 GPIO1 时钟—CCM_CCGR1 设置 GPIO1_IO03 的复用功能—IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 配置 GPIO1_IO03—IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 设置GPIO GPIO1_GDIR 的 bit3 要设置为 1,表示输出 控制GPIO输出电平,…

FastApi教程

FastApi&#xff0c;一个用于构建 API 的现代、快速&#xff08;高性能&#xff09;的web框架。 FastApi是建立在Starlette和Pydantic基础上的&#xff0c;Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库。Starlette是一种轻量级的ASGI框架/工具包&#x…

C语言 文件操作——按行读写文件

目录 按行写文件 按行读文件 按行读写文件 按行写文件 int puts ( const char *s ); 将字符串 s 写入标准输出流 stdout &#xff0c;并在其后添加一个换行符 按字符串&#xff08;行&#xff09; 写 文件 int fputs ( const char *s, FILE *fp); 将字符串 s 写入 fp 所…

轻松上手:使用 Vercel 部署 HTML 页面教程

&#x1f600; 在学习前端的过程中&#xff0c;部署项目往往是一个令人头疼的问题。然而&#xff0c;Vercel 为我们提供了一个便捷且免费的解决方案。 Vercel 是一个强大的云平台&#xff0c;专门用于前端项目的部署和托管。它不仅支持多种前端框架和静态网站生成器&#xff0…

【中标麒麟服务器操作系统实例分享】java应用DNS解析异常分析及处理

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn 情况描述 中标麒麟服务器操作系统V7运行在 ARM虚…

基于Transformer的自编码器模型在故障检测中的应用

在现代工业和制造领域&#xff0c;故障检测是保证设备和生产线安全、高效运行的关键。传统的故障检测方法往往依赖于人工经验或规则&#xff0c;然而&#xff0c;这些方法的准确性和泛化能力有限。随着深度学习技术的迅速发展&#xff0c;越来越多的智能故障检测方法应运而生&a…

Sigrity System Explorer Snip Via Pattern From Layout模式从其它设计中截取过孔模型和仿真分析操作指导

Sigrity System Explorer Snip Via Pattern From Layout模式从其它设计中截取过孔模型和仿真分析操作指导 Sigrity System Explorer Snip Via Pattern From Layout模式支持从其它设计中截取过孔模型用于仿真分析,同样以差分模板为例 具体操作如下 双击打开System Explorer软件…