jvm性能调优 - 07线上应用部署JVM实战_栈内存与永久代预估与设置

简介: jvm性能调优 - 07线上应用部署JVM实战_栈内存与永久代预估与设置

Pre

上一篇给大家基于案例分析了一下,如果我们准备上线一个新的系统,如何根据这个系统未来预估的业务量,访问量,去推算这个系统每秒种的并发量,然后推算每秒钟的请求对内存空间的占用,进而推算出整个系统运行期间的JVM内存运转模型。

然后基于这个推算出来的JVM内存运转模型,再接着去在系统上线前就选择一个合理的机器配置,要多大内存的机器,另外给JVM堆内存空间一个合理的大小。

其实这是一项非常基础的技能,因为对于大厂工程师,每次上线一个新的系统,他可能上线就会面临很大的访问压力

所以必须要学会合理预估内存压力,然后选择对应的机器配置,并且给出合理的内存大小 。



基于案例,说说不合理设置内存的反面示例

说的是一个正面的例子,即如何合理的设置内存大小。

今天来说一个反面的不合理设置内存大小导致的问题, 比如现在我们假设一个前提,就是支付系统因为没有经过合理的内存预估,所以直接选用了1台2核4G的虚拟机来部署了线上系统,而且就只用了一台机器

然后线上JVM给的堆内存大小,仅仅就只有1G,扣除老年代之后,新生代其实就几百MB的内存空间,大家看下图。


好了,接着我们还是用相同的业务压力,就是每天100万交易,高峰期每秒大概100笔支付交易,对应核心的支付订单对象有100个创建出来,每个支付订单对象占据500左右的字节大小,总共就是50kb左右。

然后一笔交易要1秒来处理,所以这100个对象在新生代中存在1秒的期间会被人引用,是无法被回收的。

而且我们之前说过一个全局预估的思路,从核心的支付订单对象扩展开来,拓展到系统里其他的对象中去,起码可以把内存占用扩大了10倍~20倍

比如我们就扩大个20倍好了,那么说明1秒之内,总共会创建出来大概1MB左右的对象,无法被回收。


大促期间,流量激增

其实按照估算出来的内存压力,你这么小的新生代在系统正常运行的情况下,其实还不算什么大问题。

因为每秒新增1MB对象,然后几百秒过后,新生代快满了,自然就会触发Minor GC,回收掉里面99%的垃圾对象。

你要是内存那么小,最多就是发现系统每隔几分钟略微卡顿一下,因为这个时候在进行垃圾回收,会影响系统性能。

但是现在我们假设,如果你的电商系统搞大促活动呢?

一般搞大促活动,很可能导致你的压力瞬间增大10倍,因为平时不来你网站的人,今天都来了。

此时可能会发现,每秒钟你的支付系统不是100笔订单了,可能是每秒钟上千笔订单。

这个时候你的系统压力本身就会很大了,不光是内存,尤其是线程资源、CPU资源,都会几乎打满。内存就更是岌岌可危了。


少数请求需要几十秒处理,导致老年代内存占用变大

咱们就针对内存来分析一下。

现在假设你每秒1000笔交易,那么每秒钟系统对内存的占用增加到10MB以上

我们甚至可以再大胆一点,预估每秒对内存占用达到几十MB,甚至上百MB也可以,因为毕竟大促时流量激增,就一切围绕这来预估。

而且最可怕的一点是,可能你每秒过来的1000笔交易,不再是1秒就可以处理完毕了,因为压力骤增,会导致你的系统性能下降,可能偶尔会出现每个请求处理完毕需要几秒钟,甚至几十秒的时间。

此时我们看下图可能出现什么问题,假设你的新生代里已经积压了很多的数据,都快满了。


然后呢,此时内存里有比如几十MB的对象都被人引用着,因为少数请求突然处理的特别慢。

为什么会处理特别慢?因为压力太大,导致系统性能太差了,如下图。


这个时候,如果你要再次在新生代里分配对象,那么是不是会导致一次Minor GC去回收新生代?

没错,但是可能回收掉大量的对象之后,那少数几十MB的对象还在,因为少数请求特别的慢。

然后很快新生代继续被填满,再次触发Minor GC,然后少数几十MB的对象还在,此时多次之后后,就会被转移到老年代去,如下图。



老年代对象越来越多导致频繁垃圾回收

那么大家思考一下,上述流程如果反复来多次,就是时不时有少数请求特别慢,创建的对象在新生代反复多次没法被回收,然后就会被弄到老年代去

然后后续处理完之后,老年代里的对象就没人引用了,成为了垃圾对象。

经常重复这个流程,老年代里的垃圾对象,是不是就会越来越多?

一旦老年代的垃圾对象越来越多,迟早会满,然后就会触发老年代的垃圾回收,而且这个老年代被占满的频率还很快,可能就会频繁触发老年代的垃圾回收。

大家要知道,老年代的垃圾回收速度是很慢的,后面我们分析。

但是在上述场景下,我们基本可以分析出来,如果你不合理的设置内存,就会导致新生代内存不充足,然后导致很多对象不停的迁移到老年代去,最后导致老年代也要不停的进行垃圾回收。

最后这频繁的垃圾回收,就会极大的影响系统的性能。


小结

通过一个支付系统内存设置过小,然后突发巨大的流量压力,突发的性能抖动,最后导致很多对象长期在新生代被人引用,无法被回收,最后持续进入老年代,最后触发老年代内存都频繁占满,然后老年代都频繁被垃圾回收。

所以大家更能从反面体会到,不合理的预估 业务系统压力,不合理的设置内存大小,就可能会导致很大的问题。


如何合理设置永久代大小?

话说回来,如何合理设置永久代大小呢?

其实一般永久代刚开始上线一个系统,没太多可以参考的规范,但是一般你设置个几百MB,大体上都是够用的

因为里面主要就是存放一些类的信息,后面分析什么样的系统容易出现永久代内存溢出。


如何合理设置栈内存大小

其实这个栈内存大小设置,一般也不会特别的去预估和设置的,一般默认就是比如512KB到1MB,就差不多够了

这就是每个线程自己的栈内存空间,用来存放线程执行方法期间的各种布局变量的。后面介绍栈内存什么时候会发生内存溢出。


思考

自己负责的系统的内存压力,然后就是JVM内存大小是否合理,如果业务暴增100倍,是否会有内存问题。

自己画出核心业务流程图,然后一点点去分析,这是一个非常重要的技能。 其实JVM实战技能里的第一步,就是合理预估系统内存压力,合理设置JVM内存大小。


相关文章
|
25天前
|
缓存 算法 Java
Java内存管理与调优:释放应用潜能的关键
【4月更文挑战第2天】Java内存管理关乎性能与稳定性。理解JVM内存结构,如堆和栈,是优化基础。内存泄漏是常见问题,需谨慎管理对象生命周期,并使用工具如VisualVM检测。有效字符串处理、选择合适数据结构和算法能提升效率。垃圾回收自动回收内存,但策略调整影响性能,如选择不同类型的垃圾回收器。其他优化包括调整堆大小、使用对象池和缓存。掌握这些技巧,开发者能优化应用,提升系统性能。
|
1月前
|
编解码 算法 Java
构建高效的Android应用:内存优化策略详解
随着智能手机在日常生活和工作中的普及,用户对移动应用的性能要求越来越高。特别是对于Android开发者来说,理解并实践内存优化是提升应用程序性能的关键步骤。本文将深入探讨针对Android平台的内存管理机制,并提供一系列实用的内存优化技巧,以帮助开发者减少内存消耗,避免常见的内存泄漏问题,并确保应用的流畅运行。
|
1月前
|
人工智能 关系型数据库 Serverless
Serverless 应用引擎常见问题之AI应用限制人为限制内存如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
29 3
|
29天前
|
存储 缓存 Java
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
37 1
|
1月前
|
存储 算法 编译器
【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
47 0
|
29天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
79 0
|
4天前
|
定位技术 Python
Pyglet综合应用|推箱子游戏之关卡图片载入内存
Pyglet综合应用|推箱子游戏之关卡图片载入内存
13 0
|
5天前
|
存储 安全 Java
JVM之本地方法栈和程序计数器和堆
JVM之本地方法栈和程序计数器和堆
9 0
|
9天前
|
缓存 监控 Java
深入理解Java虚拟机(JVM)性能调优
【4月更文挑战第18天】本文探讨了Java虚拟机(JVM)的性能调优,包括使用`jstat`、`jmap`等工具监控CPU、内存和GC活动,选择适合的垃圾回收器(如Serial、Parallel、CMS、G1),调整堆大小和新生代/老年代比例,以及代码优化和JIT编译策略。通过这些方法,开发者能有效提升应用性能并应对复杂性挑战。性能调优是持续过程,需伴随应用演进和环境变化进行监控与优化。
|
9天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。
16 0