danxill/php-meminfo-analyzer

用于分析meminfo转储文件的工具,它是bitone/mem-info项目的一部分

v1.0.2 2021-10-28 08:19 UTC

This package is auto-updated.

Last update: 2024-09-28 14:41:17 UTC


README

该存储库使用来自https://github.com/BitOne/php-meminfo的一些代码来简化集成

使用方法

转储内存内容

meminfo_dump(fopen('/tmp/my_dump_file.json', 'w'));

此函数以JSON格式生成PHP内存的转储。此转储可以由提供的分析器稍后分析。

此函数接受一个流句柄作为参数。它允许您指定一个文件(例如fopen('/tmp/file.txt', 'w')),以及使用php://stdout流使用标准输出。

显示内存中项目的摘要

$ bin/analyzer summary <dump-file>

Arguments:
  dump-file             PHP Meminfo Dump File in JSON format

示例

$ bin/analyzer summary /tmp/my_dump_file.json
+----------+-----------------+-----------------------------+
| Type     | Instances Count | Cumulated Self Size (bytes) |
+----------+-----------------+-----------------------------+
| string   | 132             | 7079                        |
| MyClassA | 100             | 7200                        |
| array    | 10              | 720                         |
| integer  | 5               | 80                          |
| float    | 2               | 32                          |
| null     | 1               | 16                          |
+----------+-----------------+-----------------------------+

显示具有最大子项数量的对象列表

$ bin/analyzer top-children [options] [--] <dump-file>

Arguments:
  dump-file             PHP Meminfo Dump File in JSON format

Options:
  -l, --limit[=LIMIT]   limit [default: 5]

示例

$ bin/analyzer top-children /tmp/my_dump_file.json
+-----+----------------+----------+
| Num | Item ids       | Children |
+-----+----------------+----------+
| 1   | 0x7ffff4e22fe0 | 1000000  |
| 2   | 0x7fffe780e5c8 | 11606    |
| 3   | 0x7fffe9714ef0 | 11602    |
| 4   | 0x7fffeab63ca0 | 3605     |
| 5   | 0x7fffd3161400 | 2400     |
+-----+----------------+----------+

查询内存转储以查找特定对象

$ bin/analyzer query [options] [--] <dump-file>

Arguments:
  dump-file              PHP Meminfo Dump File in JSON format

Options:
  -f, --filters=FILTERS  Filter on an attribute. Operators: =, ~. Example: class~User (multiple values allowed)
  -l, --limit=LIMIT      Number of results limit (default 10).
  -v                     Increase the verbosity

示例

$ bin/analyzer query -v -f "class=MyClassA" -f "is_root=0" /tmp/php_mem_dump.json
+----------------+-------------------+------------------------------+
| Item ids       | Item data         | Children                     |
+----------------+-------------------+------------------------------+
| 0x7f94a1877008 | Type: object      | myObjectName: 0x7f94a185cca0 |
|                | Class: MyClassA   |                              |
|                | Object Handle: 1  |                              |
|                | Size: 72 B        |                              |
|                | Is root: No       |                              |
+----------------+-------------------+------------------------------+
| 0x7f94a1877028 | Type: object      | myObjectName: 0x7f94a185cde0 |
|                | Class: MyClassA   |                              |
|                | Object Handle: 2  |                              |
|                | Size: 72 B        |                              |
|                | Is root: No       |                              |
+----------------+-------------------+------------------------------+
| 0x7f94a1877048 | Type: object      | myObjectName: 0x7f94a185cf20 |
|                | Class: MyClassA   |                              |
...

显示引用路径

引用路径是内存中特定项(通过其指针地址标识)与所有中间项之间的路径,直到连接到程序中仍存活变量的项。

此路径显示哪些项负责特定项的内存泄漏。

$ bin/analyzer ref-path <item-id> <dump-file>

Arguments:
  item-id               Item Id in 0xaaaaaaaa format
  dump-file             PHP Meminfo Dump File in JSON format

Options:
  -v                     Increase the verbosity

示例

$ bin/analyzer ref-path -v 0x7f94a1877068 /tmp/php_mem_dump.json
Found 1 paths
Path from 0x7f94a1856260
+--------------------+
| Id: 0x7f94a1877068 |
| Type: object       |
| Class: MyClassA    |
| Object Handle: 4   |
| Size: 72 B         |
| Is root: No        |
| Children count: 1  |
+--------------------+
         ^
         |
         3
         |
         |
+---------------------+
| Id: 0x7f94a185cb60  |
| Type: array         |
| Size: 72 B          |
| Is root: No         |
| Children count: 100 |
+---------------------+
         ^
         |
    second level
         |
         |
+--------------------+
| Id: 0x7f94a185ca20 |
| Type: array        |
| Size: 72 B         |
| Is root: No        |
| Children count: 1  |
+--------------------+
         ^
         |
    first level
         |
         |
+---------------------------+
| Id: 0x7f94a1856260        |
| Type: array               |
| Size: 72 B                |
| Is root: Yes              |
| Execution Frame: <GLOBAL> |
| Symbol Name: myRootArray  |
| Children count: 1         |
+---------------------------+

使用PHP Meminfo查找和理解内存泄漏的工作流程

追查内存泄漏

PHP的其他内存调试工具

  • XDebug (https://xdebug.org/) 使用跟踪功能和内存增量选项(请参阅XDebug文档),您可以跟踪函数内存使用情况。您可以使用提供的脚本来获取汇总视图(待办事项:链接)

  • PHP Memprof (https://github.com/arnaud-lb/php-memory-profiler) 提供关于函数内存使用的汇总数据。比XDebug的完整跟踪资源消耗要少。

故障排除

"由memory_usage条目报告了大量内存使用,但摘要中项目的累积大小远低于内存使用量"

Zend引擎本身内部使用了大量内存来编译PHP文件、运行虚拟机、执行垃圾收集器等... 另一部分内存通常由PHP扩展本身占用。剩余的内存使用量来自您程序中的PHP数据结构。

在某些情况下,某些PHP扩展可能会内部使用几百兆字节。例如PDO扩展和MySQLi扩展。默认情况下,当执行SQL查询时,它们将所有结果缓冲在PHP内存中:https://php.ac.cn/manual/en/mysqlinfo.concepts.buffering.php

如果结果数量非常多,这将消耗大量内存,而这种内存使用量并非由您程序中的对象或数组的数据引起,而是由扩展的工作方式引起的。

这是一个例子,但类似的情况也可能发生在图像处理扩展上,这些扩展将使用大量内存来转换图像。

所有扩展都使用Zend内存管理器,因此它们不会超过为PHP进程设置的内存限制。因此,它们的内存使用量包含在memory_get_usage()提供的信息中。

但PHP Meminfo只能获取PHP程序中数据结构的内存使用信息,而不是来自扩展本身。

因此,这些数字之间的差异可能相当大。

调用meminfo_dump时出现"调用未定义的函数"错误

这意味着扩展尚未启用。

检查 PHP 信息输出的 MemInfo 数据。

要查看 PHP 信息输出,只需创建一个调用 phpinfo(); 函数的页面,然后从浏览器中加载它,或者从命令行调用 php -i

为什么大多数测试都是“跳过”的?

在执行 make test 时,一些测试将需要 JSON 功能。但是编译系统通过删除所有加载扩展的配置指令来生成一个干净的 env。因此,如果 JSON 功能被打包为一个单独的扩展(而不是直接编译到 PHP 运行时中),则测试将被跳过。

您可以使用 make test 命令之后生成的 run-tests.php 运行它们,通过提供 php 可执行文件。

$ TEST_PHP_EXECUTABLE=$(which php) $(which php) run-tests.php -d extension=$PWD/modules/meminfo.so

在这种情况下,您的测试将使用您本地的 PHP 配置运行,包括加载 JSON 扩展。

请注意,当使用 PHP 8 时,这不是必需的,因为 JSON 函数现在通常直接编译到 PHP 中。

致谢

感谢 Derick Rethans 对关键的 XDebug 的启发式工作。请参阅 http://www.xdebug.org/