内存是当今世界上被广泛浪费的资源之一。 由于编程效率低下,令人吃惊的(有时是“令人震惊的”)内存浪费被浪费了。 我们看到这种模式在多个企业应用程序中重复出现。 为了证明这种情况,我们进行了一项小型研究。 我们分析了著名的spring boot pet诊所应用程序,以查看浪费了多少内存。 该应用程序是由社区设计的,旨在显示spring应用程序框架如何用于构建简单但功能强大的面向数据库的应用程序。

环境

  • Spring Boot 2.1.4。发布
  • Java SDK 1.8
  • 的Tomcat 8.5.20
  • 带有MySQL Connector / J 8.0.15的MySQL 5.7.26

压力测试

我们使用了流行的开源负载测试工具Apache JMeter进行压力测试。 我们使用以下设置执行了30分钟的负载测试:

  • 线程数(用户)– 1000(连接到目标的用户数)
  • 加速周期(以秒为单位)– 10.所有请求开始的时间范围。 根据我们的配置,每0.01秒,将启动1个新线程,即100个线程/秒。
  • 循环计数–永远。 这1000个线程背对背执行测试迭代。
  • 持续时间(秒)-1800。 加速后,1000个线程连续运行1800秒。

图:Jmeter设置

我们在负载测试中采用了以下方案:  

  • 将新的宠物主人添加到系统。
  • 查看有关宠物主人的信息。
  • 向系统添加新宠物。
  • 查看有关宠物的信息。
  • 将有关访问的信息添加到宠物的访问历史中。
  • 更新有关宠物的信息。
  • 更新有关宠物主人的信息。
  • 通过搜索其姓名查看所有者信息。
  • 查看所有所有者的信息。

如何测量内存浪费?

工业界有数百种工具可以显示所使用的内存量 。 但是我们很少遇到能够测量由于编程效率低下而浪费的内存量的工具。 HeapHero是一个简单的工具,可以分析堆转储并告诉您由于编程效率低而浪费了多少内存。

测试运行时,我们从Spring Boot Pet Clinic应用程序捕获了堆转储。 (有7种不同的选项可从Java / Android应用程序 捕获堆转储 。您可以选择最方便的选项)。

我们将捕获的堆转储上传到HeapHero工具中。 工具生成了这个漂亮的报告,显示由于效率低下的编程浪费了65%的内存。 是的,这是一个简单的原始应用程序,应该在其中实现了所有最佳实践,在一个著名的框架上也浪费了65%的内存。

图:由HeapHero生成的图表,显示65%的内存被Spring Boot宠物诊所应用程序浪费了

分析内存浪费

从报告中,您可以注意到以下内容:

  • 字符串重复导致浪费了15.6%的内存
  • 由于原始数组效率低下,浪费了14.6%的内存
  • 由于重复的原始数组浪费了14.3%的内存
  • 由于收集效率低下,浪费了12.1%的内存

在此Spring启动应用程序 (和大多数企业应用程序)中浪费内存的主要原因是字符串重复。 该报告显示了由于重复字符串而浪费了多少内存,它们是什么字符串,谁在创建它们以及如何对其进行优化。

无花果:重复的字符串

您会注意到由于重复的字符串浪费了15.6%的内存。 请注意

  • 'Goldi'字符串已被创建207,481次。
  • “访问”字符串已创建132,308次。 “访问”是我们在测试脚本中提到的描述。
  • “班加罗尔”字符串已创建75,374次。 “ Banglore”是我们在测试脚本中指定的城市名称。
  • '123123123'已被创建37,687次。
  • “ Mahesh”字符串已创建37,687次。

显然,“ Goldi”是通过测试脚本在屏幕上输入的宠物的名称。 “访问”是通过测试脚本在屏幕上输入的描述。 同样,是值。 但是有一个问题,为什么要创建相同的字符串对象那么几千次。

我们都知道字符串是不可变的(即一旦创建,就无法修改)。 鉴于为什么要创建成千上万个重复的字符串?

HeapHero工具还报告创建这些重复字符串的代码路径。

无花果:重复字符串源自的代码路径

这是修复应用程序中重复字符串的高级建议 。 您可以采用适用于您的应用程序的策略。

在弹簧靴宠物诊所应用中造成内存浪费的另一个主要原因是收集效率低下。 以下是HeapHero报告的摘录:

图:由于收集效率低而浪费的内存

您会注意到,内存中99%的LinkedHashSet中没有任何元素。 如果没有元素,为什么还要创建LinkedHashSet? 当您创建一个新的LinkedHashSet对象时,将在内存中保留16个元素的空间。 现在为这16个元素保留的所有空间都被浪费了。 如果对LinedHashset进行延迟初始化,则不会出现此问题。

不良做法:

 private LinkedHashSet<String, String>myHashSet = new LinkedHashSet();  public void addData(String key, String value) {  myHashSet.put(key, value);  } 

最佳实践:

 private LinkedHashSet<String, String>myHashSet;  public void addData(String key, String value) { If (myHashSet == null ) {  myHashSet = new LinkedHashSet(); }  myHashSet.put(key, value);  } 

同样,另一个观察结果是:68%的ArrayList中仅包含1个元素。 创建ArrayList对象时,将在内存中保留10个元素的空间。 这意味着在88%的ArrayList中9个元素的空间被浪费了。 如果可以使用容量初始化ArrayList,则可以避免此问题。

不良做法:使用默认值初始化集合。

 new ArrayList(); 

最佳实践:使用容量初始化集合

 new ArrayList( 1 ); 

内存不便宜

一个人可以反驳说,内存是如此便宜,那么为什么我要担心它呢? 公平的问题。 但是在云计算时代,我朋友的记忆并不便宜。 有4种主要的计算资源:

  1. 中央处理器
  2. 记忆
  3. 网络
  4. 存储

您的应用程序可能在AWS EC2实例上运行的数十万个应用程序服务器上运行。 在上述4种计算资源中,哪个资源在EC2实例中已饱和? 我要求您在这里稍等一下,然后再继续阅读。 考虑一下,首先确定哪些资源已饱和。

对于大多数应用程序,它是*内存*。 CPU始终为30 – 60%。 总是有大量的存储空间。 很难饱和网络(除非您的应用程序正在流式传输大量视频内容)。 因此,对于大多数应用程序来说,首先是内存饱和。 即使CPU,存储和网络未充分利用,仅由于内存变得饱和,您最终还是会配置越来越多的EC2实例。 这将使您的计算成本增加几倍。

另一方面,由于编程效率低下,现代应用程序无一例外地浪费了30%-90%的内存。 即使在没有太多业务逻辑的Spring Boot宠物诊所之上,也浪费了65%的内存。 实际的企业应用程序将浪费相似的数量,甚至更多。 因此,如果您可以编写内存有效的代码,那么它将降低您的计算成本。 由于内存是第一个达到饱和的资源,因此,如果可以减少内存消耗,则可以在较少数量的服务器实例上运行应用程序。 您也许可以减少30 – 40%的服务器。 这意味着您的管理层可以减少30%-40%的数据中心(或云托管提供商)成本,再加上维护和支持成本。 它可以节省数百万/数十亿美元的成本。

结论

除了减少计算成本,编写内存效率高的代码后,您的客户体验也将变得更好。 如果您可以减少为服务新的传入请求而创建的对象数量,则响应时间将大大缩短。 由于创建的对象较少,因此在创建和垃圾回收对象上将花费较少的CPU周期。 减少响应时间将提供更好的客户体验。

翻译自: https://www.javacodegeeks.com/2019/11/memory-wasted-by-spring-boot-application.html

Spring Boot应用程序浪费了内存相关推荐

  1. spring_Spring Boot应用程序浪费了内存

    spring 内存是当今世界上广泛浪费的资源之一. 由于编程效率低下,浪费了令人惊讶的(有时是"震撼"的)内存. 我们看到这种模式在多个企业应用程序中重复出现. 为了证明这种情况, ...

  2. Spring Boot之程序性能监控

    转载自 Spring Boot之程序性能监控 Spring Boot特别适合团队构建各种可快速迭代的微服务,同时为了减少程序本身监控系统的开发量,Spring Boot提供了actuator模块,可以 ...

  3. SpringBoot之二:部署Spring Boot应用程序方式

    衡量多种部署方式 Spring Boot应用程序有多种构建和运行方式,其中一些你已经使用过了. 在IDE中运行应用程序(涉及Spring ToolSuite或IntelliJ IDEA). 使用Mav ...

  4. buildpack_使用Buildpack容器化Spring Boot应用程序

    buildpack 在本文中,我们将看到如何使用Buildpacks容器化Spring Boot应用程序. 在先前的一篇文章中,我讨论了Jib . Jib允许我们在不使用Dockerfile的情况下将 ...

  5. compose应用_带有PostgreSQLDocker Compose for Spring Boot应用程序

    compose应用 在此博客文章中,您将学习如何使用PostgreSQL配置Spring Boot应用程序以与Docker Compose一起运行. 这篇博客文章涵盖: Spring Boot应用程序 ...

  6. apache ignite_Kubernetes集群上的Apache Ignite和Spring第1部分:Spring Boot应用程序

    apache ignite 在之前的一系列博客中,我们在Kubernetes集群上启动了一个Ignite集群. 在本教程中,我们将使用先前在Spring Boot Application上创建的Ign ...

  7. aws 删除ec2实例_如何在AWS EC2实例上部署Spring Boot应用程序

    aws 删除ec2实例 你好朋友, 在本教程中,我们将看到如何在AWS EC2实例上部署Spring Boot应用程序. 这是我们将要执行的步骤. 1.使用Spring Boot Initialise ...

  8. cognito_将Spring Boot应用程序与Amazon Cognito集成

    cognito 在本文中,我们将展示如何使用Spring Security 5.0中引入的OAuth 2.0客户端库 ,在Spring Boot应用程序中为身份验证用户使用Amazon Cognito ...

  9. docker jib_Jib –为Spring Boot应用程序构建docker映像

    docker jib 使用Jib为示例Spring Boot应用程序创建docker映像是如此容易,这让我感到惊喜. 让我首先将Jib与以前使用的方法进行对比. 我正在使用bmuschko出色的gra ...

最新文章

  1. Revit:从入门到精通学习教程
  2. SQL Server 2008 的CDC功能
  3. R语言dplyr包的mutate函数将列添加到dataframe中或者修改现有的数据列:基于条件判断创建布尔型指示变量、将异常离散编码转化为NA值
  4. android--------内存泄露分析工具—Android Monitor
  5. 解惑(一) ----- super(XXX, self).__init__()到底是代表什么含义
  6. 任务——μ/COS-II读书笔记
  7. 卷积和池化matlab 实现,UFLDL新版教程与编程练习(七):Convolution and Pooling(卷积和池化)...
  8. 【设计模式】C++单例模式
  9. 【Flink】大数据分析常用去重算法分析『HyperLogLog 篇』
  10. java用hashmap_Java集合之HashMap的用法
  11. Android 屏幕实现水龙头事件
  12. C实现NV12转I420
  13. 关于ccs软件的简单使用
  14. tensorflow或运算 tf.logical_or tf.math.logical_or
  15. 前端用到的单词(读音+意思)
  16. 新手学Windows XP
  17. 如何强制重启M1 Mac MacBook Pro?
  18. 2-eggs-100-floors-puzzle(扔两个鸡蛋问题)
  19. elementplus 上传文件
  20. java多用户商城 微商城 大型B2B2C商城平台系统源码

热门文章

  1. ssl提高组周六模拟赛【2018.9.15】
  2. CSP-S 2021 退役记
  3. 【并查集】家谱(luogu 2814/ssl 2343)
  4. [清华集训2017]无限之环(网络流)
  5. Java的并发编程中的多线程问题到底是怎么回事儿?
  6. 再有人问你volatile是什么,把这篇文章也发给他(深入分析)
  7. 独占锁、共享锁、更新锁,乐观锁、悲观锁
  8. Oracle入门(十四)之PL/SQL
  9. 一个java源文件中可以声明多少个class与编译后会生成多少个字节码文件
  10. 插值查找+代码实现+注意事项