Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

内存泄漏分析器-memory-tracker #853

Open
guanhui07 opened this issue Nov 30, 2024 · 0 comments
Open

内存泄漏分析器-memory-tracker #853

guanhui07 opened this issue Nov 30, 2024 · 0 comments

Comments

@guanhui07
Copy link
Owner

guanhui07 commented Nov 30, 2024

内存泄漏分析器

常驻内存 分析内存泄漏还是非常有必要的,比如使用workerman swoole 等 cli 应用程序 很多人多少都会遇到内存泄漏
而一般大多人选择解决方法就是定期 重启。简单粗暴解决。。

memory-tracker

Swoole Tracker 是由上海识沃科技公司开发的一款PHP性能分析、调用统计分析、链路追踪软件。
该软件已于2023年正式下线。在此项目下线后,有很多PHP开发者向我们反馈需要用其
分析cli守护进程程序下的内存泄漏问题。在2024年11月我们将内存泄漏分析器从Swoole Tracker
剥离出来,更名为php-memory-tracker并作为新的单独扩展,提供给开发者来使用。
另外我们也对此工具进行了重构,新的4.0版本使用更简单可靠,还增加了泄漏点调用栈的输出,更加强大。

新的php-memory-tracker扩展,既可用于swoole协程环境,也可用于非协程环境,
例如workerman或其他cli常驻进程程序。


支持PHP的7.3以上版本 
仅支持cli环境加载,避免php-fpm误加载
增加了泄漏点调用栈的输出

下载 安装

https://doc.swoole.com/@memory-tracker/download.html
忽略

下载扩展后,修改php.ini加入extension=memory_tracker即可,
可使用php -m和php --ri memory_tracker命令查看扩展是否安装成功。


php --ri memory_tracker

memory_tracker

memory_tracker support => enabled
Copyright => 上海识沃网络科技有限公司
Email => [email protected]
Website => https://www.swoole.com/
Version => 4.0.0

Directive => Local Value => Master Value
memory_tracker.enable => Off => Off


使用

使用时只需要加入-d memory_tracker.enable=1,并且在常驻进程的
主循环中加入memory_tracker_leak_check函数调用即可。

demo.php

class ClassA
{
    public array $arr = [];
    public string $str = '';
}

function foo(ClassA $obj)
{
    $str = str_repeat("big string", 1024);
    $obj->arr[] = $str;
    $obj->str .= $str;
}

$obj = new ClassA();
$usage = memory_get_usage();
$n = 100;
while ($n--) {
    foo($obj);
}

var_dump(strlen($obj->str));
var_dump(memory_get_usage() - $usage);
memory_tracker_leak_check();

执行:

# 不开启内存检测,不会有性能消耗
php cli.php 
int(1024000)
int(2259616)

# 开启检测
php -d memory_tracker.enable=1 cli.php 

int(1024000)
int(2264608)
[Round#0] leak 1000.03 KB bytes, alloc 99 times at /home/swoole/workspace/ext/memory_tracker/examples/cli.php:13
#0 /home/swoole/workspace/ext/memory_tracker/examples/cli.php(20): foo(Object(ClassA))

[Round#0] leak 1003.12 KB bytes, alloc 100 times at /home/swoole/workspace/ext/memory_tracker/examples/cli.php:11
#0 /home/swoole/workspace/ext/memory_tracker/examples/cli.php(11): str_repeat('big string', 1024)
#1 /home/swoole/workspace/ext/memory_tracker/examples/cli.php(20): foo(Object(ClassA))

Swoole 协程环境

class Test
{
    public $arr = [];

    function run()
    {
        $locals = '';
        $this->run2($locals);
    }

    function run2(&$locals)
    {
        global $global1, $global2;
        $http = new \Swoole\Http\Server("0.0.0.0", 9501, SWOOLE_BASE);
        $http->set([
            'worker_num' => 1
        ]);
        $http->on("start", function ($server) {

        });
        $http->on("request", function ($req, $resp) use (&$global1, &$global2, &$locals) {
            $global2 .= "2222222222";
            $locals .= "333333333333";
            $global1[] = random_bytes(random_int(256, 4096));
            $this->arr[] = "444444444";
            $resp->end("hello world");

            memory_tracker_leak_check(128);
        });

        $http->start();
    }
}

(new Test())->run();

执行:

php -d memory_tracker.enable=1 co_server.php
发起请求:

ab -c 5 -n 5000 http://127.0.0.1:9501/
检测结果:

[Round#2913] leak 275.73 KB bytes, alloc 128 times at /home/swoole/workspace/ext/memory_tracker/examples/co_server.php:47
#0 [internal function]: Test->{closure}(Object(Swoole\Http\Request), Object(Swoole\Http\Response))

[Round#2944] leak 34.54 KB bytes, alloc 128 times at /home/swoole/workspace/ext/memory_tracker/examples/co_server.php:46
#0 [internal function]: Test->{closure}(Object(Swoole\Http\Request), Object(Swoole\Http\Response))

[Round#2944] leak 28.79 KB bytes, alloc 128 times at /home/swoole/workspace/ext/memory_tracker/examples/co_server.php:45
#0 [internal function]: Test->{closure}(Object(Swoole\Http\Request), Object(Swoole\Http\Response))

循环引用

const N = 200;
class testA
{
    public $pro;
}
function foo()
{
    var_dump(memory_get_usage());
    for ($i = 0; $i < N; $i++) {
        $obj = new testA();
        $obj->pro = $obj;
        unset($obj);

        memory_tracker_leak_check(64);
    }
    var_dump(memory_get_usage());
}
foo();
执行:
php -d memory_tracker.enable=1 gc.php 
int(2109824)
[Round#63] leak 3.50 KB bytes, alloc 64 times at /home/swoole/workspace/ext/memory_tracker/examples/gc.php:12
#0 /home/swoole/workspace/ext/memory_tracker/examples/gc.php(20): foo()

[Round#96] leak 3.50 KB bytes, alloc 64 times at /home/swoole/workspace/ext/memory_tracker/examples/gc.php:12
#0 /home/swoole/workspace/ext/memory_tracker/examples/gc.php(20): foo()

[Round#129] leak 3.50 KB bytes, alloc 64 times at /home/swoole/workspace/ext/memory_tracker/examples/gc.php:12
#0 /home/swoole/workspace/ext/memory_tracker/examples/gc.php(20): foo()

[Round#161] leak 3.50 KB bytes, alloc 64 times at /home/swoole/workspace/ext/memory_tracker/examples/gc.php:12
#0 /home/swoole/workspace/ext/memory_tracker/examples/gc.php(20): foo()

[Round#194] leak 3.50 KB bytes, alloc 64 times at /home/swoole/workspace/ext/memory_tracker/examples/gc.php:12
#0 /home/swoole/workspace/ext/memory_tracker/examples/gc.php(20): foo()

int(2131392)

可以看到无论是复杂的循环引用,还是普通的数组、字符串无限扩容导致的内存泄漏,无论是普通的cli脚本,
亦或者是Swoole协程服务器环境,memory_tracker都可以正常工作,
除了打印申请内存的脚本文件和行数之外,还会打印申请内存时的调用栈。

https://doc.swoole.com/@memory-tracker/download.html

https://doc.swoole.com/@memory-tracker/usage.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant