关于内存溢出:故障分析-MySQL-耗尽主机内存一例分析

作者:付祥 现居珠海,次要负责 Oracle、MySQL、mongoDB 和 Redis 保护工作。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 异常现象开发人员反馈,有一台服务器内存简直被 MySQL 耗尽了,执行 top 命令,输入如下: 这台机器是个测试环境,MySQL 是开发本人装置的,数据库版本 5.6.51 ,机器总内存32G,MySQL 占了29G。 剖析过程查看 MySQL 启动工夫发现1个星期前才启动,猜想之前因为主机内存耗尽触发了 OOM ,查看 MySQL 谬误日志,发现每隔10几天,MySQL 就异样敞开一次: 2022-02-24 03:03:42 20981 [Note] InnoDB: Database was not shutdown normally!2022-03-13 02:31:40 4134 [Note] InnoDB: Database was not shutdown normally!2022-03-31 02:31:08 6846 [Note] InnoDB: Database was not shutdown normally!2022-04-12 02:31:41 1159 [Note] InnoDB: Database was not shutdown normally!2022-04-23 04:41:51 6773 [Note] InnoDB: Database was not shutdown normally!2022-05-04 02:31:52 2499 [Note] InnoDB: Database was not shutdown normally!2022-05-13 04:56:06 23010 [Note] InnoDB: Database was not shutdown normally!2022-05-30 02:31:33 3244 [Note] InnoDB: Database was not shutdown normally!查看操作系统日志,进一步验证了 MySQL 耗尽主机内存,触发 OOM : ...

July 5, 2022 · 5 min · jiezi

12内存溢出与内存泄漏

内存溢出与内存泄露一、内存溢出一种程序运行出现的错误。当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误。 二、内存泄漏占用的内存没有及时释放。内存泄露积累多了就容易导致内存溢出。常见的内存泄露: 意外的全局变量。没有及时清理的计时器或回调函数。闭包// 1. 内存溢出var obj = {}for (var i = 0; i < 10000; i++) { obj[i] = new Array(10000000) console.log('-----')}// 2. 内存泄露// 意外的全局变量,没有加varfunction fn() { a = new Array(10000000) console.log(a)}fn()// 3. 没有及时清理的计时器或回调函数var intervalId = setInterval(function () { //启动循环定时器后不清理 console.log('----')}, 1000)// clearInterval(intervalId)// 4. 闭包function fn1() { var a = 4 function fn2() { console.log(++a) } return fn2}var f = fn1()f()// f = null

June 27, 2019 · 1 min · jiezi

Bitmap之位图采样和内存计算详解

原文首发于微信公众号:jzman-blog,欢迎关注交流!Android 开发中经常考虑的一个问题就是 OOM(Out Of Memory),也就是内存溢出,一方面大量加载图片时有可能出现 OOM, 通过采样压缩图片可避免 OOM,另一方面,如一张 1024 x 768 像素的图像被缩略显示在 128 x 96 的 ImageView 中,这种做法显然是不值得的,可通过采样加载一个合适的缩小版本到内存中,以减小内存的消耗,Bitmap 的优化主要有两个方面如下: 有效的处理较大的位图缓存位图这篇文章主要侧重于如何有效的处理较大的位图。 此外,在 Android 中按照位图采样的方法加载一个缩小版本到内存中应该考虑因素? 估计加载完整图像所需要的内存加载这个图片所需的空间带给其程序的其他内存需求加载图片的目标 ImageView 或 UI 组件的尺寸当前设备的屏幕尺寸或密度位图采样图像有不同的形状的和大小,读取较大的图片时会耗费内存。读取一个位图的尺寸和类型,为了从多种资源创建一个位图,BitmapFactory 类提供了许多解码的方法,根据图像数据资源选择最合适的解码方法,这些方法试图请求分配内存来构造位图,因此很容易导致 OOM 异常。每种类型的解码方法都有额外的特征可以让你通过 BitMapFactory.Options 类指定解码选项。当解码时设置 inJustDecodeBounds 为true,可在不分配内存之前读取图像的尺寸和类型,下面的代码实现了简单的位图采样: /** * 位图采样 * @param res * @param resId * @return */public Bitmap decodeSampleFromResource(Resources res, int resId){ //BitmapFactory创建设置选项 BitmapFactory.Options options = new BitmapFactory.Options(); //设置采样比例 options.inSampleSize = 200; Bitmap bitmap = BitmapFactory.decodeResource(res,resId,options); return bitmap;}注意:其他 decode... 方法与 decodeResource 类似,这里都以 decodeRedource 为例。 ...

June 20, 2019 · 5 min · jiezi

一次性能优化:吞吐量从1提升到2500

性能优化,简而言之,就是在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短。压测也是检验一个架构设计是否合理的一个重要方法。项目介绍这个项目是一个线下支付的交易系统,使用线下设备发起支付。项目使用SpringMVC+Dubbo的微服务开发模式,其中SpringMvc作为Web端部署在tomcat上对外提供rest服务,其他模块使用dubbo开发,SpringMVC调用dubbo服务完成业务功能。优化目的这一次的性能优化,目的是在不调整业务逻辑的情况下通过压力测试的方式测试下单时接口的性能能达到多少,如果有性能问题,就要在不修改业务逻辑的情况下通过优化各项参数的方式(包括JVM优化、数据库连接数和Dubbo连接数)来提升整体性能。压测前的准备压力测试策略采用循序渐进的方式,逐渐增加并发量的方式,先以1个并发开始,慢慢增加,当达到瓶颈的时候就进行参数调整和优化。建立压测分支压测优化过程中,可能随时需要调整配置参数,可能会对一些配置参数进行修改或者对公共代码进行优化。为了不让其他研发人员的开发受到干扰,在git上基于release分支建立了feature_stress分支,专门用来压测过程中,参数配置调优使用,不影响其他研发人员的开发。搭建压测环境为了不不影响研发和测试人员的工作,单独申请了三台4C32G的虚拟机进行压力测试,一台部署tomcat,一台部署dubbo服务,一台部署mysql。为什么只申请单机部署的方式压测呢?因为本次测试的目的是看单台服务器的性能情况,优化的目的是将单台服务器的性能最大化。准备测试脚本本次测试选用jmeter作为测试工具进行压力测试,由测试人员模拟线下支付的流程写好测试脚本。初步压测很保守的,从1个并发开始压测,测试结果让人非常的惊喜,压测开始几分钟后,就出现大量的连接失败,无法继续测试。出现大量的内存溢出的异常。没出现异常时的吞吐量达到了1req/s。同时,通过jconsole控制台监控tomcat,发现其线程数最高到了2万多个。问题分析这个异常是创建本地线程失败抛出的异常,为什么有这么大量的线程呢?不合常理呀!于是查看对应的代码,原来这是一个自定义的一个人日志Appender,在这个Appender里使用了线程池,这个Appender本来的目的是使用多线程提升日志性能,并且将所有的日志都收集到一个文件中。代码类似如下:log4j.properties中直接将新的Appender添加到了rootLogger下:初步优化通过以上代码和日志配置文件就能看出来,每次日志输出都会创建线程,这就是线程为什么越来越多,最后导致无法创建新的本地线程的原因。为了不影响现有的功能,将LogAppender类append方法中的线程池创建的部分变成了类的属性,并固定只用8个线程:提交代码重新部署压测环境,再进行压测,吞吐量马上就上来了,达到了1700req/s,][7]深入调优经过上面的优化之后,整体的性能还不是很高,经过jconsole监控发现,线程数还是很高,虽然没有2万那么多了,但还是有3000多的线程,这么多的线程根本无法发挥机器的性能,时间都浪费在线程切换上了,通过查看线程栈发现大量的线程都是dubbo连接的线程,为什么如此之多呢?查看dubbo的配置文件,consumer的链接数都设置成了1000,于是将所有dubbo的consumer连接数均改为了64。同时将log4j.properties中配置了控制台输出的都关闭了。最终的优化后的测试结果,最高达到了2600req/s。总结性能优化需要从几个方面考虑:CPU是否有瓶颈,本项目没有大量的计算,所以CPU没有瓶颈。IO是否是瓶颈,线程太多或者连接太多都是瓶颈,本项目中并发时创建了大量的线程,达到了服务器的最高可用的连接数,导致内存溢出了,创建太多的线程也会让CPU把时间都浪费在线程切换上了。生产环境不要使用控制台输出,因为控制台输出是同步的,输出太多会对性能有很大的影响。如果出现吞吐量小的情况可以输出线程栈,看看到底是block在哪里了,是调用服务时间长还是读写数据库时间长。———— / END / ————

December 4, 2018 · 1 min · jiezi