shm_get_var返回拷贝还是引用?

本文目的

本文探讨了php标准扩展sysvshm库中的函数shm_get_var返回变量的copy还是reference

 

问题背景

php标准扩展中的sysvshm提供了php访问共享内存的能力,而且数据的最小粒度是变量,这样可以免去手动变量序列化和反序列化,比另一个标准扩展shmop好使用。但是,如果假设有一个50M的数组放到共享内存中,反复的访问此变量,是否会影响系统性能?如果shm_get_var返回的是变量引用,那么性能开销不大,因为每次返回的都只是内存的“指针”,不会拷贝真实数据。如果返回的是copy呢?那么每访问一次,就需要拷贝50M左右的内存,如果访问频率过大,那么就会导致性能瓶颈。

 

验证

到底返回什么,通过下面的代码,可以得到验证:

<?php
$arr = array(0,1,2,3,4,5,6);

if(!($nShmID = shm_attach(ftok(__FILE__, 'i'), 1024))) {
	die("create shared memory failed.\n");
}

$nVarKey = 1;
if(!shm_put_var($nShmID, $nVarKey, $arr)) {
	die("failed to put var\n");
}


if(!($arr1 = shm_get_var($nShmID, $nVarKey))) {
	die("failed to get arr1\n");
}
array_pop($arr1);


if(!($arr2 = shm_get_var($nShmID, $nVarKey))) {
	die("failed to get arr2\n");
}


if ($arr != $arr2) {
	echo "get a copy\n";
} else {
	echo "get a reference\n";
}


if(!shm_remove($nShmID)) {
	die("failed to remove shared memory\n");
}
?>

 

执行结果如下:

shm_get_var返回拷贝还是引用?

所以,很明显,返回的是copy而不是reference。

 

原始代码

为什么会返回copy呢?可以看看shm_get_var的c代码实,文件位置PHP_SRC/ext/sysvshm/sysvshm.c,如下:

/* {{{ proto mixed shm_get_var(resource id, int variable_key)
Returns a variable from shared memory */
PHP_FUNCTION(shm_get_var)
{
	zval *shm_id;
	long shm_key;
	sysvshm_shm *shm_list_ptr;
	char *shm_data;
	long shm_varpos;
	sysvshm_chunk *shm_var;
	php_unserialize_data_t var_hash;


	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
		return;
	}
	SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);

	/* setup string-variable and serialize */
	/* get serialized variable from shared memory */
	shm_varpos = php_check_shm_data((shm_list_ptr->ptr), shm_key);

	if (shm_varpos < 0) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", shm_key);
		RETURN_FALSE;
	}

	shm_var = (sysvshm_chunk*) ((char *)shm_list_ptr->ptr + shm_varpos);
	shm_data = &shm_var->mem;


	PHP_VAR_UNSERIALIZE_INIT(var_hash);
	if (php_var_unserialize(&return_value, (const unsigned char **) &shm_data, (unsigned char *) shm_data + shm_var->length, &var_hash TSRMLS_CC) != 1) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable data in shared memory is corrupted");
		RETVAL_FALSE;
	}
	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
}
/* }}} */

从上面的代码,可以知道shm_get_var的内部实现会调用php_var_unserialize进行反序列化,也就表示变量其实还是以序列化后的字节流形式存放在共享内存中,这样必然无法返回变量引用,只能返回拷贝。shm_get_var只是为我们做了反序列化工作,本质上与shmop_read一样。

 

结论

由于php_get_var返回的是变量拷贝,如果需要反复访问共享内存中的较大的变量时,最好换一种存储策略,因为共享内存会重复拷贝数据,造成不必要的性能开销。

 

参考资料

*: Does PHP copy variables when retrieving from shared memory?


本文转自bourneli博客园博客,原文链接:http://www.cnblogs.com/bourneli/archive/2012/08/05/2623939.html,如需转载请自行联系原作者

上一篇:我谈软件测试


下一篇:中国移动架构师大数据分析模型实践:解决渠道猫和老鼠的游戏