SpringBoot 在一次 http 请求中耗费了多少内存?

  • SpringBoot 在一次 http 请求中耗费了多少内存?
    • 先说说为啥会关心这个问题
    • 先搞懂:一次 HTTP 请求,SpringBoot 到底在干啥?
    • 动手测:最简单的接口,到底耗多少内存?
      • 第一步:准备测试代码
      • 第二步:测试结果
      • 第三步:加一点业务逻辑,再测
    • 影响内存消耗的几个关键因素
    • 我是怎么优化的?
    • 最后聊聊我的看法
      • 总结

SpringBoot 在一次 http 请求中耗费了多少内存?

最近一直在琢磨一个问题:我们平时写的 SpringBoot 接口,处理一次普通的 HTTP 请求到底要耗多少内存?之前只关注接口快不快、会不会报错,从没细算过内存账,这两天抽时间测了下,聊聊我的发现,不一定全对,就是自己的一点心得。

先说说为啥会关心这个问题

其实一开始我也没当回事,直到有次压测小接口,明明 CPU 使用率才 30% 多,服务却开始频繁卡顿,看监控发现堆内存涨得飞快,才意识到“单次请求内存消耗”这事儿不能忽略。在我看来,哪怕单次耗得少,高并发下积少成多,也可能让 JVM 频繁 GC,甚至 OOM,所以还是有必要搞清楚的。

先搞懂:一次 HTTP 请求,SpringBoot 到底在干啥?

要算内存账,得先知道请求进来后,SpringBoot 都创建了哪些东西。我简单梳理了下,一个普通的 GET 请求过来,至少会有这些开销:

  1. Tomcat 接请求,创建 Request/Response 对象;
  2. SpringMVC 解析请求参数,创建 HandlerMethod、参数绑定相关的对象;
  3. 我们自己写的 Service、Mapper 层对象,还有查询出来的业务数据对象;
  4. 日志对象、上下文对象(比如 RequestContextHolder);
  5. 请求处理完,这些对象大多会变成垃圾,等 GC 回收。

这些对象加起来,就是一次请求的内存消耗核心部分。

动手测:最简单的接口,到底耗多少内存?

光说不练假把式,我写了个最基础的 SpringBoot 接口,啥业务逻辑都没有,就返回个字符串,来测测内存消耗。

第一步:准备测试代码

先建个普通的 SpringBoot 项目,引入 web 依赖,然后写个接口:

@RestController@RequestMapping("/test")publicclassTestController{// 记录初始内存(单位:字节)privatelonginitialMemory=0;@GetMapping("/empty")publicStringemptyRequest(){// 获取当前线程的内存使用(堆内存)Runtimeruntime=Runtime.getRuntime();if(initialMemory==0){// 第一次请求,记录初始内存(避免初始化影响)initialMemory=runtime.totalMemory()-runtime.freeMemory();return"初始化完成";}// 处理请求时的内存longcurrentMemory=runtime.totalMemory()-runtime.freeMemory();// 单次请求消耗 = 当前内存 - 初始内存longconsume=currentMemory-initialMemory;// 打印消耗(转成 KB,方便看)System.out.println("单次空请求内存消耗:"+consume/1024+" KB");return"ok";}}

第二步:测试结果

启动项目后,先访问一次/test/empty做初始化,然后再访问几次,得到的结果大概是:
第一次(初始化后):约 10~20 KB
后续多次访问:稳定在 2~5 KB 左右

这个结果还挺意外的,纯空请求居然也要耗这么点内存?后来我查了下,主要是 Tomcat 和 SpringMVC 底层的对象开销,哪怕没业务逻辑,这些基础对象还是要创建的。

第三步:加一点业务逻辑,再测

光测空接口没意义,我再加个简单的业务逻辑,比如查询个列表(模拟真实场景):

// 模拟业务对象classUser{privateLongid;privateStringname;privateIntegerage;// 省略 getter/setter}@GetMapping("/with-data")publicList<User>withDataRequest(){Runtimeruntime=Runtime.getRuntime();longstartMemory=runtime.totalMemory()-runtime.freeMemory();// 模拟查询10个用户数据List<User>userList=newArrayList<>();for(inti=0;i<10;i++){Useruser=newUser();user.setId((long)i);user.setName("测试用户"+i);user.setAge(20+i);userList.add(user);}// 计算消耗longendMemory=runtime.totalMemory()-runtime.freeMemory();longconsume=endMemory-startMemory;System.out.println("带10个User对象的请求内存消耗:"+consume/1024+" KB");returnuserList;}

这次测试结果大概是:单次消耗约 30~50 KB。
能看出来,业务数据对象是内存消耗的大头,对象越多、字段越复杂,耗得就越多。

影响内存消耗的几个关键因素

测完之后,我总结了下,影响单次请求内存消耗的因素主要有这些:

  1. 请求参数和返回数据:参数越多、返回的 JSON 数据越大(比如列表里的对象多),内存耗得越多,这是最直观的;
  2. 中间件和框架开销:比如用了 RedisTemplate、MyBatis,这些框架会创建连接对象、Mapper 代理对象,都会占内存;
  3. 日志和监控:如果日志级别设为 DEBUG,会创建大量日志字符串对象;加了 SkyWalking、Pinpoint 这类监控,也会多一层对象开销;
  4. 线程本地变量(ThreadLocal):如果代码里用了 ThreadLocal 没及时清理,对象会一直占着内存,直到线程销毁;
  5. 临时对象:比如循环里创建字符串、List 没复用,会产生大量临时对象,虽然 GC 能回收,但高并发下还是会增加内存压力。

我是怎么优化的?

知道了消耗点,我们的经验是从这几个地方入手优化:

  1. 复用对象:比如频繁创建的 List、Map,用 ThreadLocal 缓存起来复用,避免每次请求都 new;
  2. 控制返回数据量:分页查询一定要做,别一次性返回几千条数据,不仅耗内存,网络传输也慢;
  3. 减少不必要的对象创建:比如字符串拼接用 StringBuilder,别用 “+” 号;循环里别创建匿名内部类;
  4. 及时清理 ThreadLocal:在请求结束时(比如用 @AfterReturning 切面)清理 ThreadLocal,避免内存泄漏;
  5. 调整 JVM 参数:比如设置合适的堆内存大小(-Xms、-Xmx),让 GC 更高效,减少内存碎片。

举个简单的优化例子,复用 List 对象:

// 优化前:每次请求都new ArrayList@GetMapping("/bad")publicList<User>badRequest(){List<User>list=newArrayList<>();// 每次都创建新对象// 业务逻辑...returnlist;}// 优化后:复用ThreadLocal里的ListprivateThreadLocal<List<User>>userListLocal=ThreadLocal.withInitial(ArrayList::new);@GetMapping("/good")publicList<User>goodRequest(){List<User>list=userListLocal.get();list.clear();// 清空复用// 业务逻辑...returnlist;}// 请求结束后清理@AfterReturning("/good")publicvoidclean(){userListLocal.remove();}

最后聊聊我的看法

其实问“一次请求耗多少内存”,没有固定答案,我认为核心不是纠结具体的数字,而是要有“内存意识”——知道哪些代码会耗内存,高并发下该怎么优化。

普通的业务接口,单次消耗几十 KB 其实很正常,只要不是几百 KB 甚至几 MB,一般都没问题。但如果是每秒几千、几万的高并发接口,哪怕单次只耗 10 KB,一秒钟也会耗掉几十 MB 内存,这时候就得精打细算了。

总的来说,SpringBoot 本身的基础开销是固定的,我们能优化的主要是业务代码里的对象创建和数据传输量。写代码时多留意一下,别随手 new 对象,别返回多余的数据,就能少耗不少内存。

总结

  1. SpringBoot 处理一次 HTTP 请求的内存消耗分两部分:框架基础开销(空请求约 2~5 KB)+ 业务对象开销(随数据量增加);
  2. 影响内存消耗的核心是返回数据量、临时对象创建、中间件开销这几点;
  3. 优化的关键是复用对象、控制数据量、及时清理 ThreadLocal,不用追求极致的内存消耗,重点是避免不必要的浪费。

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

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

相关文章

Socket 编程客户端篇:Connect 隐式绑定与数据发送实战

各类资料学习下载合集 链接:https://pan.quark.cn/s/7c8c391011eb Socket 编程客户端篇:Connect 隐式绑定与数据发送实战 如果说服务器是“坐地经营”的店家(被动等待),那么客户端就是“上门拜访”的顾客(主动发起)。在 Socket 编程中,客户端的开发流程相对简洁,但其…

茶叶商城|基于springboot 茶叶商城系统(源码+数据库+文档)

茶叶商城 目录 基于springboot vue茶叶商城系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue茶叶商城系统 一、前言 博主介绍&#xff1a;✌️大…

294. Java Stream API - 对流进行归约

文章目录294. Java Stream API - 对流进行归约&#x1f3af; 什么是归约&#xff08;Reduction&#xff09;&#xff1f;✅ 什么是终端操作&#xff1f;&#x1f514; 注意事项&#xff1a;&#x1f9e0; 使用 BinaryOperator 对流进行归约&#x1f9ea; 示例一&#xff1a;经典…

百考通AI开题报告功能:智能构建研究蓝图,轻松搞定高质量开题

撰写开题报告&#xff0c;是每位学生迈入正式研究前必须跨越的关键门槛。它不仅要清晰界定研究问题&#xff0c;还需系统梳理文献、科学设计方法、合理规划路径&#xff0c;并阐明研究价值——任何一个环节的疏漏&#xff0c;都可能导致开题受阻。然而&#xff0c;面对繁杂的学…

百考通AI开题报告功能:用智能写作破解“开题难”,高效开启科研之旅

“开题报告怎么写&#xff1f;”——这是无数学生在科研起步阶段最常面临的困惑。选题方向模糊、文献综述杂乱、研究方法空泛、逻辑结构松散……这些问题不仅拖慢进度&#xff0c;还容易导致开题反复修改甚至被退回。如今&#xff0c;百考通AI平台推出的“开题报告”写作功能&a…

农产品销售数据分析|基于Python 农产品销售数据分析系统(源码+数据库+文档)

农产品销售数据分析 目录 基于PythonDjango农产品销售数据分析系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于PythonDjango农产品销售数据分析系统 一、前言 博…

百考通AI开题报告功能:智能生成专业框架,让开题写作事半功倍

开题报告是学术研究的“第一块基石”&#xff0c;它不仅决定课题能否顺利立项&#xff0c;更直接影响后续研究的深度与方向。然而&#xff0c;对许多学生而言&#xff0c;撰写开题报告却是一场充满挑战的“硬仗”&#xff1a;选题太大难以聚焦、文献堆砌缺乏主线、研究方法描述…

基于STM32的车内环境检测和儿童滞留报警系统(开题报告)

本科毕业论文(设计)开题报告 姓名 学号 专业 通信工程 题目 基于STM32的车内环境检测和儿童滞留报警系统 选题意义、研究现状及可行性分析 1、选题意义 汽车在给人们出行带来便利的同时也引发了一些儿童安全问题,尤其是由于父母的疏忽导致儿童被锁车内致危的事件频发。儿童滞…

ACPI!ACPIBuildProcessRunMethodPhaseCheckSta和ACPI!ACPIGetConvertToDevicePresence调试断点搜集

ACPI!ACPIBuildProcessRunMethodPhaseCheckSta和ACPI!ACPIGetConvertToDevicePresence调试断点搜集ACPI!ACPIBuildDeviceExtension ACPI!ACPIDetectPdoDevices ACPI!ACPIDetectPdoDevices0x122ACPI!ACPIBuildDeviceDpcACPI!ACPIBuildProcessGenericList 关键1 ACPI!ACPI…

校园食堂点餐|基于Python 校园食堂点餐系统(源码+数据库+文档)

校园食堂点餐 目录 基于PythonDjango校园食堂点餐系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于PythonDjango校园食堂点餐系统 一、前言 博主介绍&#xff1a…

python基于django校园二手交易平台管理系统

目录基于Django的校园二手交易平台管理系统摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;基于Django的校园二手交易平台管理系统摘要 校园二手交易平台是为高校学生提供的便捷…

百考通AI开题报告功能:告别“开题卡壳”,智能生成逻辑清晰、结构完整的专业初稿

对许多学生来说&#xff0c;开题报告是毕业路上的第一道“难关”——明明有研究想法&#xff0c;却不知如何系统表达&#xff1b;读了不少文献&#xff0c;却理不清研究脉络&#xff1b;想设计方法&#xff0c;却写得空洞模糊。结果往往是反复修改、进度拖延&#xff0c;甚至因…

计算机毕业设计hadoop+spark+hive旅游推荐系统 旅游可视化系统 地方旅游网站 旅游爬虫 旅游管理系统 大数据毕业设计 机器学习 深度学习 知识图谱

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 技术范围&#xff1a;Sprin…

YOLOv11_OBB(目标旋转框)模型从标签制作到训练推理

前言 由于目前全网大都是水平框检测的教程&#xff0c;本博客使用YOLOv11_OBB检测&#xff0c;从打标签&#xff0c;到训练自己的数据集&#xff0c;显示目标的旋转框检测教程。 目标检测框和目标旋转框的区别&#xff1a; 旋转边界框&#xff08;OBB&#xff09;包含一个额外的…

从ACPI!AMLILoadDDB中的ACPI!SyncLoadDDB到ACPI!ACPICallBackLoad

从ACPI!AMLILoadDDB中的ACPI!SyncLoadDDB到ACPI!ACPICallBackLoadrc LoadDDB(pctxt,pDSDT, gpnsNameSpaceRoot, &powner);if (rc STATUS_SUCCESS){rc SyncLoadDDB(pctxt);}#ifdef DEBUG{KIRQL oldIrql;gdwfAMLI & ~AMLIF_LOADING_DDB;KeAcquireSpinLock( &gdw…

百考通AI开题报告功能:智能构建学术起点,让高质量开题触手可及

开题报告是科研工作的“导航图”&#xff0c;它不仅框定研究边界、明确问题意识&#xff0c;还体现研究者的逻辑思维与学术素养。然而&#xff0c;现实中许多学生在撰写时常常陷入“有想法却写不出”“读了很多却理不清”“方法模糊结构散”的困境&#xff0c;导致开题反复修改…

IP分片与组装

IP 分片是 TCP/IP 协议栈中网络层&#xff08;IP 层&#xff09;的核心机制&#xff0c;目的是解决 “IP 报文长度超过数据链路层 MTU 限制” 的传输问题 —— 确保大型 IP 数据报能通过不同 MTU 的网络链路&#xff08;如以太网、PPP 链路&#xff09;成功送达目标主机。以下从…

jQuery 版本文件及相关信息汇总

一、核心结论​ 截至2025年1月&#xff0c;jQuery 的最新稳定版本为 3.7.1&#xff08;2023年7月发布&#xff09;&#xff0c;4.0 版本仍处于测试阶段&#xff08;2025年8月发布 Release Candidate 1&#xff0c;未正式推出&#xff09;。当前主流使用的版本为 3.x 系列&…

python基于django框架的健康档案网站的设计与实现

目录健康档案网站的设计与实现摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;健康档案网站的设计与实现摘要 基于Django框架的健康档案网站旨在为用户提供便捷的个人健康数据管…

ARP欺骗的原理与防御措施

ARP 欺骗&#xff08;也叫 ARP 毒化&#xff09;的核心是利用ARP 协议无身份验证的漏洞&#xff08;主机收到 ARP 应答时&#xff0c;会直接更新自身 ARP 缓存表&#xff0c;不管是否发送过对应请求&#xff09;&#xff0c;让攻击者&#xff08;图中 “主机 M”&#xff09;伪…