Spring Boot 应用程序浪费的内存
内容提要
本文讨论了Spring Boot应用程序中的内存浪费问题,通过分析发现65%的内存被浪费,主要原因是字符串重复和低效的集合实现。文章提出了优化方法,如避免创建重复的字符串对象和使用容量初始化集合,以减少内存消耗并提高客户体验。
延伸解读
内存浪费的量化证据
文章通过压力测试和堆转储分析,给出了具体的内存浪费数据:65%的内存因低效编程被浪费,其中字符串重复占15.6%,低效原始数组占14.6%,重复原始数组占14.3%,低效集合占12.1%。这些数字来自对Spring Boot Pet Clinic这一示例应用的实测,说明即使是被广泛认可的框架和示例项目,也存在显著优化空间。读者可借此意识到,内存浪费并非抽象概念,而是可测量、可定位的具体问题。
重复字符串的规模与成因
报告显示,某些字符串被创建了数十万次,例如“Goldi”出现207,481次,“Visit”出现132,308次。字符串不可变,每次创建新实例都会占用堆内存。文章指出HeapHero能报告创建这些重复字符串的代码路径,暗示问题源于代码中反复构造相同字符串值。这提醒开发者,在处理用户输入或固定描述时,应关注字符串对象的复用,而非无意识地重复创建。
集合初始化的常见陷阱
文章指出,99%的LinkedHashSet没有任何元素,却因默认预留16个元素空间而造成浪费;68%的ArrayList只含1个元素,却预留了10个元素空间。解决方案是懒初始化或指定容量初始化。这些例子说明,集合的默认构造函数可能在不经意间放大内存占用,尤其是在大量创建小集合的场景下。开发者应养成按需初始化或指定初始容量的习惯。
内存成本与业务影响
文章强调,在云计算环境中内存并不便宜,且内存往往是首先饱和的资源。即使CPU、存储和网络利用率低,内存饱和也会迫使增加实例,推高计算成本。若能减少30%-40%的内存消耗,可能减少相应比例的服务器实例,从而降低数据中心或云托管成本。此外,减少对象创建还能缩短响应时间,因为创建和垃圾回收对象消耗CPU周期。这表明内存优化不仅关乎成本,也直接影响用户体验。
Q&A
Spring Boot Pet Clinic 应用的内存浪费比例是多少?
根据 HeapHero 工具分析,Spring Boot Pet Clinic 应用浪费了 65% 的内存。
Spring Boot 应用内存浪费的主要原因有哪些?
主要原因是字符串重复(15.6%)、低效的原始数组(14.6%)、重复的原始数组(14.3%)和低效的集合(12.1%)。
如何避免创建重复的字符串以减少内存浪费?
文章指出字符串重复是内存浪费的首要原因,例如“Goldi”被创建了 207,481 次。应避免在循环或频繁调用的代码中创建相同的字符串对象,但未给出具体代码示例。
低效的集合实现如何导致内存浪费?如何优化?
许多 LinkedHashSet 和 ArrayList 被创建但未有效利用。例如,99% 的 LinkedHashSet 没有元素,却预留了 16 个元素的空间;68% 的 ArrayList 只包含 1 个元素,却预留了 10 个元素的空间。优化方法包括懒初始化集合和使用指定容量初始化集合,如 new ArrayList(1)。
为什么在云计算时代需要关注内存浪费?
内存是云计算中首先饱和的资源,CPU、存储和网络通常利用率较低。内存饱和会导致需要配置更多实例,从而增加计算成本。编写内存效率高的代码可以减少服务器数量,降低 30-40% 的成本。
编写内存效率高的代码对客户体验有什么好处?
减少创建的对象数量可以缩短响应时间,因为用于创建和垃圾回收对象的 CPU 周期减少了,从而改善客户体验。