上篇内容介绍了在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下载
|