PHP 常驻内存泄漏分析定位

在使用常驻内存框架需要注意什么?

  • 内存释放

  • 数据污染

  • 资源释放

  • 静态变量保存的对象不会被释放,需要手动管理

  • 禁止使用exit和die

  • 禁止使用sleep时间长的函数,防止导致Worker进程退出

  • 不同Worker进程创建的对象和连接是不能互通的,创建连接池需要注意

  • 定义公共函数的时候要使用 function_exists 判断函数是否存在,否则会提示重名

  • 类引入文件需要使用 include_once 或者 require_once 否则会提示类名重复

  • 修改代码需要重启服务才能生效

  • echo、print_r、var_dump不会输出到浏览器

  • 使用$_GET、$_POST、$_REQUEST、$_SESSION、$_COOKIE、$_SERVER等$_开头的变量没有值

常驻内存和php-fpm模式有什么区别?

注意常驻内存php-fpm
变量不释放自动释放
对象只new一次每次请求都需要重新new
单例在初始化阶段把对象存到内存每个请求重建创建和销毁对象

PHP 内存泄漏分析定位

  • 场景一 程序操作数据过大
  • 场景二 程序操作大数据时产生拷贝
  • 场景三 配置不合理系统资源耗尽
  • 场景四 无用的数据未及时释放

场景一:程序操作数据过大

情景还原:一次性读取超过php可用内存上限的数据导致内存耗尽

<?php
ini_set('memory_limit', '128M');
$string = str_pad('1', 128 * 1024 * 1024);
?>

问题现象:特定数据处理时可复现,做任何IO操作都有可能遇到此类问题,比如:一次mysql 查询返回大量数据、一次把大文件读取进程序等。 

场景二:程序操作大数据时产生拷贝

情景还原:执行过程中对大变量进行了复制(COW机制),导致内存不够用。

<?php
ini_set("memory_limit",'1M');

$string = str_pad('1', 1* 750 *1024);
$string2 = $string;
$string2 .= '1';

问题现象:局部代码执行过程中占用内存翻倍。

问题分析

php 是写时复制(Copy On Write),也就是说,当新变量被赋值时内存不发生变化,直到新变量的内容被操作时才会产生复制。

解决方法

及早释放无用变量,或者以引用的形式操作原始数据。

<?php
ini_set("memory_limit",'1M');

$string = str_pad('1', 1* 750 *1024);
$string2 = $string;
unset($string);
$string2 .= '1';

场景三:配置不合理系统资源耗尽

  • 情景还原:因配置不合理导致内存不够用,2G 内存机器上设置最大可以启动 100 个 php-fpm 子进程,但实际启动了 50 个 php-fpm 子进程后无法再启动更多进程
  • 问题现象:线上业务请求量小的时候不出现问题,请求量一旦很大后部分请求就会执行失败
  • 解决方法:合理设置 post_max_size、max_file_uploads、upload_max_filesize、max_input_vars、max_input_nesting_level 等参数并调优 php-fpm 相关参数。

场景四:无用的数据未及时释放

情景还原:这种问题从程序逻辑上不是问题,但是无用的数据大量占用内存导致资源不够用,应该有针对性的做代码优化。

问题现象:程序运行期间内存逐渐增长,程序结束后内存正常释放。

问题分析

此类问题不易察觉,定位困难,尤其是有些框架封装好的方法,要明确其适用场景。

解决方法

本例中要通过DB::listen方法获取所有执行的 SQL 语句记录并写入日志,但此方法存在内存泄露问题,在开发环境下无所谓,在生产环境下则应停用,改用其他途径获取执行的 SQL 语句并写日志。

场景五:清理内存碎片

即使unset了所有变量,内存仍然无法降下去,代码如下

<?php
function main()
{
    for ($i = 1; $i < 2000000; $i++) {
        $GLOBALS[$i] = str_repeat("str_repeat这个函数会申请内存,但我马上就unset掉", 10);
    }
    for ($i = 1; $i < 2000000; $i++) {
        unset($GLOBALS[$i]);
		// 强制进行垃圾回收
    }
}
echo "内存使用量:".memory_get_usage()."\n";
main();
echo "unset后内存使用量:".memory_get_usage()."\n";
if (gc_enabled()) {
    echo "垃圾回收已开启。\n";

    // 强制进行垃圾收集
    gc_collect_cycles();
    // 清理内存缓存
    gc_mem_caches();
} else {
    echo "垃圾回收未开启。\n";
}
echo "gc后内存使用量:".memory_get_usage()."\n";
?>

咋回事呢?根本原因是产生了内存碎片,和 PHP 的内存分配算法有关,这里不展开讲,大概原理是:小于 3072 字节的内存申请 PHP 会认为是小内存,PHP 会把所有申请的小内存块缓存起来,即使释放了也不归还给操作系统,以保证内存管理的效率

解决方法

最后如果遇到了内存碎片话问题,可以尝试用gc_mem_caches()函数,手动清除掉。

ENVI软件在遥感影像处理中扮演着至关重要的角色,其中影像的几何纠正功能对于确保影像数据的确性至关重要。几何纠正的过程涉及调整影像坐标,使其与实际地理坐标系统一致,这一步骤对于后续的分析和制图至关重要。 参考资源链接:[ENVI遥感影像处理全面指南:预处理、信息提取与三维可视化](https://wenku.youkuaiyun.com/doc/398pr5x5h3?spm=1055.2569.3001.10343) 具体步骤如下: 1. 打开ENVI软件,导入需要进行几何纠正遥感影像。 2. 选择相应的工具,例如“Basic Tools”菜单下的“Geometric Correction”选项。 3. 根据影像数据类型和需要达到的度,选择合适的纠正方法。ENVI提供了多种纠正算法,包括多项式模型、共线方程、地面控制点(GCP)校正等。 4. 如果使用GCP校正,需要在影像上选择若干地面控制点,并输入这些点的实际地理坐标,作为校正的基础。 5. 进行校正参数的计算,这个过程通常涉及到解算一个或多个多项式方程,以最小化影像中的点与真实地理坐标间的偏差。 6. 使用计算得到的参数进行影像的重新采样和配准,最终输出几何校正后的影像。 7. 校正结果需要评估,一般通过比较校正前后GCP的残差来验证校正度和效果。 适用场景: 几何纠正广泛应用于地形变化检测、土地利用调查、城市规划、环境监测等多个领域。在这些应用场景中,影像的几何准确性直接影响到分析结果的可靠性。 为了深入学习ENVI中遥感影像几何纠正的更多细节和高级应用,推荐参考《ENVI遥感影像处理全面指南:预处理、信息提取与三维可视化》一书。该指南不仅提供了理论知识,还详细介绍了操作步骤和实际应用案例,有助于读者全面掌握几何纠正的技巧和方法。 参考资源链接:[ENVI遥感影像处理全面指南:预处理、信息提取与三维可视化](https://wenku.youkuaiyun.com/doc/398pr5x5h3?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值