Linux下php环境dio_read读取串口出现内存溢出的解决办法

上篇内容介绍了在Linux环境下可以通过PHP的dio模块实现串口数据采集

CentOS Linux下使用PHP实现串口通信(serial)_zgh419566的博客-CSDN博客

为此我特定编写了服务程序,但是发现服务运行一段时间会异常退出

经排查系统报错 "Fatal Error: Allowed memory size of xxxxxx bytes exhausted"

通过跟踪问题,发现php_dio函数存在内存溢出现象

通过研究别人写的程序  tty_uart.c  https://github.com/WCHSoftGroup/tty_uart

/**
 * libtty_read - read data from uart
 * @fd: file descriptor of tty device
 *
 * The function return the number of bytes read if success, others if fail.
 */
static int libtty_read(int fd)
{
	int nwrite, nread;
	char buf[1024];
	int i;
	
	nread = read(fd, buf, sizeof(buf));
	if (nread >= 0) {
		if (newLine) { printf("\n************************* read nread %d bytes.\n", nread); }
	} else {
		printf("read error: %d\n", nread);
		return nread;
	}

	if (verbose) {
		for (i = 0; i < nread; i++){
			printf("%.2x", (uint8_t)buf[i]);
		}
	}

	return nread;
}

而php_dio官方代码是

/* {{{ proto string dio_read(resource fd[, int n])
   Read n bytes from fd and return them, if n is not specified, read 1k */
PHP_FUNCTION(dio_read)
{
	zval     *r_fd;
	php_fd_t *f;
	char     *data;
	zend_long      bytes = 1024;
	ssize_t   res;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &r_fd, &bytes) == FAILURE) {
		return;
	}

	if ((f = (php_fd_t *) zend_fetch_resource(Z_RES_P(r_fd), le_fd_name, le_fd)) == NULL) {
		RETURN_FALSE;
	}

	if (bytes <= 0) {
		php_error_docref(NULL, E_WARNING, "Length parameter must be greater than 0.");
		RETURN_FALSE;
	}

	data = emalloc(bytes + 1);
	res = read(f->fd, data, bytes);
	if (res <= 0) {
		efree(data);
		RETURN_NULL();
	}

	data = erealloc(data, res + 1);
	data[res] = 0;

	RETURN_STRINGL(data, res);
	efree(data);
}
/* }}} */

明显的看见官方的php_dio存在内存分配和回收的情况,怀疑这里有BUG

于是照着tty_uart的代码做了一些修改:

/* {{{ proto string dio_read(resource fd[, int n])
   Read n bytes from fd and return them, if n is not specified, read 1k */
PHP_FUNCTION(dio_read)
{
	zval     *r_fd;
	php_fd_t *f;
	char     data[4096];
	zend_long      bytes = 1024;
	ssize_t   res;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &r_fd, &bytes) == FAILURE) {
		return;
	}

	if ((f = (php_fd_t *) zend_fetch_resource(Z_RES_P(r_fd), le_fd_name, le_fd)) == NULL) {
		RETURN_FALSE;
	}

	if (bytes <= 0) {
		php_error_docref(NULL, E_WARNING, "Length parameter must be greater than 0.");
		RETURN_FALSE;
	}

	//data = emalloc(bytes + 1);
	res = read(f->fd, data, bytes);
	if (res <= 0) {
		//efree(data);
		RETURN_NULL();
	}

	//data = erealloc(data, res + 1);
	//data[res] = 0;

	RETURN_STRINGL(data, res);
	//efree(data);
}
/* }}} */

经过几天的运行,PHP程序一直能够稳定的读取串口数据,并且内存占用率一直保存在1460KB左右,非常的稳定。

 备注:通过研究,CentOS LInux内核默认只对串口保存4096字符的内容,因此我们的程序读取数据也设置最大读取 4096字节(翻倍,为了稳定)。

在此将稳定的代码放出来给大家使用。

dio-0.2.0_解决dio_read内存溢出问题-其它文档类资源-CSDN下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值