Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 1379|回复: 0

swoole 内存泄露的问题有没有好的办法解决

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-7-8 15:33:18 | 显示全部楼层 |阅读模式
     在传统的web开发模式中,我们知道,每一次php请求,都要经过php文件从磁盘上读取、初始化、词法解析、语法解析、编译等过程,而且还要与nginx或者apache通信,如果再涉及数据库的交互,还要再算上数据库的握手、验权、关闭等操作,可见一次请求的背后其实是有相当繁琐的过程,无疑,这个过程也就带来了相当多的开销!当然,所有的这些资源和内存,在一次请求结束之前,都会得到释放。

    但是,swoole是常驻内存运行的。这有几点不同,我们分别了解下。

    在运行server之后所加载的任何资源,都会一直持续在内存中存在。也就是说假设我们开启了一个server,有100个client要connect,加载一些配置文件、初始化变量等操作,只有在第一个client连接的时候才有这些操作,后面的client连接的时候就省去了重复加载的过程,直接从内存中读取就好了。

    这样好不好呢?很明显非常好,如此一来还可以提升不小的性能。

    但是,对开发人员的要求也更高了。因为这些资源常驻内存,并不会像web模式下,在请求结束之后会释放内存和资源。也就是说我们在操作中一旦没有处理好,就会发生内存泄漏,久而久之就可能会发生内存溢出。

    之前一直对swoole印象不错,没想到都是坑。其实这都不算坑,如果你觉得是坑,权且当做是一种提升自身能力的约束好了。

    回到我们的开篇提到的问题上,再啰嗦的解释一遍:server一开始就把我们的代码加载到内存中了,无论后期我们怎么修改本地磁盘上的代码,客户端再次发起请求的时候,永远都是内存中的代码在生效,所以我们只能终止server,释放内存然后再重启server,重新把新的代码加载到内存中,如此,明白否?

    那有同学要说了,感觉好麻烦,是不是说在swoole中申请的内存啥的都要自己手动unset释放呢?

    对于局部变量,就没必要操这个心了,swoole会在事件回调函数返回之后释放。但是对于全局变量你就要悠着点了,因为他们在使用完之后并不会被释放。不会被释放?那在php中,这几种全局变量:global声明的变量,static声明的对象属性或者函数内的静态变量和超全局变量谁还敢用?一个不小心服务器直接就玩完的节奏!

    我们想一下为什么要用全局变量?

    是不是就是想全局共享?但是,在多进程开发模式下,进程内的全局变量所用的内存那也是保存在子进程内存堆的,也并非共享内存,所以在swoole开发中我们还是尽量避免使用全局变量!

    那我要是非用不可呢?就是乐意,就是想用。

    我们看看如何避免内存泄漏。

    比如有一个static大数组,用于保存客户端的连接标识。我们就可以在onClose回调内清理变量。

    此外,swoole还提供了max_request机制,我们可以配置max_request和task_max_request这两个参数来避免内存溢出。

    max_request的含义是worker进程的最大任务数,当worker进程处理的任务数超过这个参数时,worker进程会自动退出,如此便达到释放内存和资源的目的。

    不必担心worker进程退出后,没“人”处理业务逻辑了,因为我们还有Manager进程,Worker进程退出后Manager进程会重新拉起一个新的Worker进程。

    task_max_request针对task进程,含义同max_request。

    光溜溜的说了半天,我们来看下是不是这么玩的。

    server的代码简写如下

    client代码如下

    为了方便测试,我们开了一个Worker进程,一个Task进程,Worker进程的最大任务设置为3次,Task进程的最大任务设置为4次。

    运行server后,在client未请求前我们看下当前的进程结构

    注意进程id等于15644和15645哦,这两个一个是Worker进程,一个是Task进程。Mac下我们就不区分到底谁是谁了。

    随后我们让客户端请求3次,再看下结果

    有没有发现原先进程id等于15645的现在变成15680了?请求3次后我们确定是Worker进程自动退出了,并且Manager进程拉起了一个15680的Worker进程。

    我们再请求一次,第四次

    发现进程id等于15644的Task进程消失了,有一个新的子进程15704被重新创建了。

    看来官方没有骗人,说的都对。

    So...原来我在一开始介绍的那么多都是废话?

    不全是,因为max_request参数对server有下面几种限制条件。

    max_request只能用于同步阻塞、无状态的请求响应式服务器程序
    纯异步的Server不应当设置max_request
    使用Base模式时max_request是无效的
    其中Base模式是swoole运行模式的一种,我们主要介绍多进程模式。

    总结:

      1. 常驻内存减少了不小开销,swoole不错
      2. 应尽量避免使用全局变量,不用最好,没啥用
      3. max_request可以解决php的内存溢出问题,但是主要还是要养成释放内存的习惯,因为max_request也有限制场景
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-3 17:45 , Processed in 0.064711 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表