JVM 内存分配性能问题

发布于:2025-08-03 ⋅ 阅读:(15) ⋅ 点赞:(0)

   问题域

    在应用服务的特定场景下,JVM 内存分配不合理带来的性能表现并不会 像内存溢出问题这么突出。可以说如果你没有深入到各项性能指标中去,是很难发现其中隐 藏的性能损耗。

    JVM 内存分配不合理最直接的表现就是频繁的 GC,这会导致上下文切换等性能问题,从
而降低系统的吞吐量、增加系统的响应时间。因此, 如果你在线上环境或性能测试时,发现
频繁的 GC,且是正常的对象创建和回收,这个时候就需要考虑调整 JVM 内存分配了,
而减少 GC 所带来的性能开销。

查看 JVM 堆内存分配

我们知道了一个对象从创建至回收到堆中的过程,接下来我们再来了解下 JVM 堆内存是如
何分配的。在默认不配置 JVM 堆内存大小的情况下,JVM 根据默认值来配置当前内存大小。我们可以通过以下命令来查看堆内存配置的默认值:
java -XX:+PrintFlagsFinal -version | grep HeapSize
jmap -heap 17222

JVM 内存分配的调优过程

我们先使用 JVM 的默认配置,观察应用服务的运行情况,下面我将结合一个实际案例来讲 述。现模拟一个抢购接口,假设需要满足一个 50W 的并发请求,且每次请求会产生 30KB 对象,我们可以通过千级并发创建一个 2MB 对象的接口来模拟万级并发请求产生大量对象 的场景,具体代码如下:

@RequestMapping(value = "/test")
public String test1(HttpServletRequest request) 
{
 List<Byte[]> temp = new ArrayList<Byte[]>();
 Byte[] b = new Byte[1024*1024];
 temp.add(b);
 return "success";
}

AB 压测

分别对应用服务进行压力测试,以下是请求接口的吞吐量和响应时间在不同并发用户数下的
变化情况:

·可以看到,当并发数量到了一定值时,吞吐量就上不去了,响应时间也迅速增加。那么,在JVM 内部运行又是怎样的呢?

分析 GC 日志

此时我们可以通过 GC 日志查看具体的回收日志。我们可以通过设置 VM 配置参数,将运 行期间的 GC 日志 dump 下来,具体配置参数如下:

-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/log/heap.log

GCViewer 工具打开heap.log文件,进而查 看到具体的 GC 日志如下:

主页面显示 FullGC 发生了 13 次,右下角显示年轻代和老年代的内存使用率几乎达到了 100%。而 FullGC 会导致 stop-the-world 的发生,从而严重影响到应用服务的性能。此 时,我们需要调整堆内存的大小来减少 FullGC 的发生。

具体调优方法

调整堆内存空间减少 FullGC:通过日志分析,堆内存基本被用完了,而且存在大量 FullGC,这意味着我们的堆内存严重不足,这个时候我们需要调大堆内存空间。设置-Xms,-Xmx的大小

-Xms:堆初始大小;

-Xmx:堆最大值。
调大堆内存之后,我们再来测试下性能情况,发现吞吐量提高了 40% 左右,响应时间也降
低了将近 50%。

网站公告

今日签到

点亮在社区的每一天
去签到