Redis 报错“OutOfDirectMemoryError(堆外内存溢出) ”问题如下:

一、报错信息:

使用 Redis 的业务接口 ,产生 OutOfDirectMemoryError(堆外内存溢出),如图:

格式化后的报错信息:

{
"timestamp": "2023-04-17 22:46:36",
"status": 500,
"error": "Internal Server Error",
"message": "Java heap space",
"trace": "java.lang.OutOfMemoryError: Java heap
......
}

二、报错原因:

源码分析:

 public final class PlatformDependent {
// 直接内存大小,可通过 “-Dio.netty.maxDirectMemory”参数设置。
private static final long DIRECT_MEMORY_LIMIT; // 默认的最大直接内存大小 ,方法略。大概意思还是:先获取“Eclipse OpenJ9”的“sun.misc.VM”参数,如果没有则获取JVM的“-XX:MaxDirectMemorySize”作为默认值。
private static final long MAX_DIRECT_MEMORY = maxDirectMemory0(); static {
// 其他赋值操作,略 // 给 直接内存大小赋值,如果有设置 "-Dio.netty.maxDirectMemory" 参数,则使用用户设置的,如果没有则使用默认的
logger.debug("-Dio.netty.maxDirectMemory: {} bytes", maxDirectMemory);
DIRECT_MEMORY_LIMIT = maxDirectMemory >= 1 ? maxDirectMemory : MAX_DIRECT_MEMORY; } private static void incrementMemoryCounter(int capacity) {
if (DIRECT_MEMORY_COUNTER != null) {
long newUsedMemory = DIRECT_MEMORY_COUNTER.addAndGet(capacity); //关键判断:如果 netty内部使用的内存大小 大于 “直接内存大小”的话,就抛出 "OutOfDirectMemoryError"异常。
if (newUsedMemory > DIRECT_MEMORY_LIMIT) {
DIRECT_MEMORY_COUNTER.addAndGet(-capacity);
throw new OutOfDirectMemoryError("failed to allocate " + capacity
+ " byte(s) of direct memory (used: " + (newUsedMemory - capacity)
+ ", max: " + DIRECT_MEMORY_LIMIT + ')');
}
}
}
}

总结原因:

1)、Springboot 2.x 以后默认使用 Lettuce作为操作 redis 的客户端。它是使用 netty 进行网络通信的。

2)、从spring-boot-starter-data-redis(2.2.3.RELEASE) 依赖可以看出内置使用的确实是 Lettuce 客户端,分析源码得知,lettuce 使用的 netty 框架,引用的netty包netty-common-4.1.43.Final.jar里面有一个PlatformDependent.java类 ,底层有个-Dio.netty.maxDirectMemory 参数,会自己校验堆外内存是否大于当前服务可使用的内存,如果大于则抛出 OutOfDirectMemoryError(堆外内存溢出)。显然,这是属于 Netty(netty-common-4.1.43.Final.jar)的bug导致堆外内存溢出的。

三、解决方法:

不能使用-Dio.netty.maxDirectMemory 只调大堆外内存,这只能延迟bug出现的时机,不能完全解决该问题。想解决有如下两个方案:

1、升级 Lettuce客户端,期待新版本会解决该问题。

2、排除 Lettuce客户端,切换使用没有该问题的 Jedis 客户端。

Netty 框架性能更好,吞吐量更大,但是Springboot默认使用的Lettuce 客户端对Netty的支持不够好;

Jedis客户端虽然没有Netty更快,但胜在稳定,没有上述bug。

因此下面使用第二种解决方案:

切换使用Jedis 客户端:

在data-redis中排除lettuce,在引入jedis

		<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!--排除 lettuce -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入 jedis -->
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

四、检验结果:

压力测试:

测试结果:

解决 Redis 报“OutOfDirectMemoryError(堆外内存溢出) 成功”

Redis 报”OutOfDirectMemoryError“(堆外内存溢出)的更多相关文章

  1. Spark Shuffle 堆外内存溢出问题与解决(Shuffle通信原理)

    Spark Shuffle 堆外内存溢出问题与解决(Shuffle通信原理) http://xiguada.org/spark-shuffle-direct-buffer-oom/ 问题描述 Spar ...

  2. Java堆外内存之六:堆外内存溢出问题排查

    一.堆外内存组成 通常JVM的参数我们会配置 -Xms 堆初始内存 -Xmx 堆最大内存 -XX:+UseG1GC/CMS 垃圾回收器 -XX:+DisableExplicitGC 禁止显示GC -X ...

  3. Java堆外内存管理

    Java堆外内存管理   1.JVM可以使用的内存分外2种:堆内存和堆外内存: 堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemo ...

  4. Java堆外内存之三:堆外内存回收方法

    一.JVM内存的分配及垃圾回收 对于JVM的内存规则,应该是老生常谈的东西了,这里我就简单的说下: 新生代:一般来说新创建的对象都分配在这里. 年老代:经过几次垃圾回收,新生代的对象就会放在年老代里面 ...

  5. JVM源码分析之堆外内存完全解读

    JVM源码分析之堆外内存完全解读   寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...

  6. 从内存泄露、内存溢出和堆外内存,JVM优化参数配置参数

    内存泄漏 内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费.内存泄漏最终会导致OOM. 造成内存泄漏 ...

  7. [转]perftools查看堆外内存并解决hbase内存溢出

    最近线上运行的hbase发现分配了16g内存,但是实际使用了22g,堆外内存达到6g.感觉非常诡异.堆外内存用一般的工具很难查看,可以通过google-perftools来跟踪: http://cod ...

  8. perftools查看堆外内存并解决hbase内存溢出

    最近线上运行的hbase发现分配了16g内存,但是实际使用了22g,堆外内存达到6g.感觉非常诡异.堆外内存用一般的工具很难查看,可以通过google-perftools来跟踪: http://cod ...

  9. 【Spark篇】---Spark调优之代码调优,数据本地化调优,内存调优,SparkShuffle调优,Executor的堆外内存调优

    一.前述 Spark中调优大致分为以下几种 ,代码调优,数据本地化,内存调优,SparkShuffle调优,调节Executor的堆外内存. 二.具体    1.代码调优 1.避免创建重复的RDD,尽 ...

  10. Netty之Java堆外内存扫盲贴

    Java的堆外内存本来是高贵而神秘的东西,只在一些缓存方案的收费企业版里出现.但自从用了Netty,就变成了天天打交道的事情,毕竟堆外内存能减少IO时的内存复制,不需要堆内存Buffer拷贝一份到直接 ...

随机推荐

  1. Vue+SSM+Element-Ui实现前后端分离(2)

    前言:后台使用ssm搭建,对以前学习知识的一个回顾,与此同时来发现自己不足.这里主要采用配置文件方式进行,有部分注解. 目标:搭建ssm框架,并测试成功:(其中也有aop切面的编写) 一.开发工具 I ...

  2. 微信小程序从0到上线(一)环境搭建

    前言: 专业术语: 步骤: 1.注册开发者账号:https://mp.weixin.qq.com/cgi-bin/wx,按照提示注册即可,如果是公司身份注册,需要公对公打款验证.

  3. MFC的对话框使用Scintilla

    工作中需要做一个脚本编辑器的工具,用于代码补全.语法高亮.错误提示等功能,可以直接使用开源控件Scintilla, 网上有一些MFC的多文档使用Scintilla的例子,项目中使用的是对话框,自己实现 ...

  4. Rfost的自我介绍+软工五问

    自我介绍+软工五问 问题 解答 这个作业属于哪个课程 网工1934-软件工程 这个作业要求在哪里 作业要求 这个作业的目标 让学生对软件工程有个初步的了解,同时掌握基础的markdown语法和博客园的 ...

  5. 微信小程序 入门总结篇

      页面生命周期 Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { }, ...

  6. consul 服务注册与更新

    服务注册与发现是微服务架构中不可或缺的重要组件. 起初服务都是单节点的,不保障高可用性,也不考虑服务的压力承载,服务之间调用单纯的通过接口访问.直到后来出现了多个节点的分布式架构,起初的解决手段是在服 ...

  7. 深入理解css 笔记(完)

    一个网站,从看起来还可以,到看起来非常棒,差别在于细节.在实现了页面里 某个组件的布局并写完样式之后,不要急着继续,有意识地训练自己,以挑剔的眼光审视刚刚完成的代码.如果增加或者减少一点内边距是不是看 ...

  8. docker 镜像rabbitmq安装

    docker 镜像rabbitmq安装 1.拉取镜像 带有"mangement"的版本(包含web管理页面): docker pull rabbitmq:3.7.7-managem ...

  9. QImageReader(Writer)支持格式变少的解决方法

    首发于我的个人博客:xie-kang.com 博客内有更多文章,欢迎大家访问 原文地址 获取程序支持的图片格式: #include "mainwindow.h" #include ...

  10. C#重点语法——特性

    特性的基本理解 ************************************************************************************* 一.含义 特 ...