page contents

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

max_request可以解决php的内存溢出问题,但是主要还是要养成释放内存的习惯,因为max_request也有限制场景

attachments-2020-11-z3kco7mW5f9f9c18bc763.png

在传统的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未请求前我们看下当前的进程结构

attachments-2020-11-KTujA6gL5f9f9c519fac1.png

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

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

attachments-2020-11-h2L6WQZV5f9f9c5d28d71.png

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

我们再请求一次,第四次

attachments-2020-11-1VwoUIqN5f9f9c6eedcf7.png

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

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


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

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

  • max_request只能用于同步阻塞、无状态的请求响应式服务器程序

  • 纯异步的Server不应当设置max_request

  • 使用Base模式时max_request是无效的

  • 其中Base模式是swoole运行模式的一种,我们主要介绍多进程模式。


总结:

  • 常驻内存减少了不小开销,swoole不错

  • 应尽量避免使用全局变量,不用最好,没啥用

  • max_request可以解决php的内存溢出问题,但是主要还是要养成释放内存的习惯,因为max_request也有限制场景



  • attachments-2020-11-xD3rtB5f5f9f9bdc892fa.jpg
    原文:https://www.cnblogs.com/wadhf/p/11809003.html
  • 发表于 2020-11-02 13:41
  • 阅读 ( 383 )
  • 分类:操作系统

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1316 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章