- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
PHP uses a copy-on-modification system.
$a = (string) $a;
($a is a already string) 是否修改和复制任何内容?
特别是,这是我的问题:
参数 1 mixed
/我想允许传递非字符串并将它们转换为字符串。
但有时这些字符串非常大。所以我想省略参数的复制,它已经是一个字符串。
我可以使用版本 Foo
还是必须使用版本 Bar
?
class Foo {
private $_foo;
public function __construct($foo) {
$this->_foo = (string) $foo;
}
}
class Bar {
private $_bar;
public function __construct($bar) {
if (is_string($bar)) {
$this->_bar = $bar;
} else {
$this->_bar = (string) $bar;
}
}
}
最佳答案
答案是肯定的,它确实复制了字符串。有点……不是真的。嗯,这取决于你对“复制”的定义......
要了解发生了什么,让我们查看源代码。执行者处理变量转换 in 5.5 here .
zend_make_printable_zval(expr, &var_copy, &use_copy);
if (use_copy) {
ZVAL_COPY_VALUE(result, &var_copy);
// if optimized out
} else {
ZVAL_COPY_VALUE(result, expr);
// if optimized out
zendi_zval_copy_ctor(*result);
}
如您所见,调用使用了 zend_make_printable_zval()
如果 zval 已经是一个字符串,它就会短路。
所以执行复制的代码是(else 分支):
ZVAL_COPY_VALUE(result, expr);
现在,让我们看看the definition of ZVAL_COPY_VALUE
:
#define ZVAL_COPY_VALUE(z, v) \
do { \
(z)->value = (v)->value; \
Z_TYPE_P(z) = Z_TYPE_P(v); \
} while (0)
注意它在做什么。字符串本身是 NOT 复制的(存储在 zval 的 ->value
block 中)。它只是被引用(指针保持不变,所以字符串值相同,没有副本)。但它正在创建一个新变量(包装值的 zval 部分)。
现在,我们进入 zendi_zval_copy_ctor
称呼。它在内部自己做了一些有趣的事情。注意:
case IS_STRING:
CHECK_ZVAL_STRING_REL(zvalue);
if (!IS_INTERNED(zvalue->value.str.val)) {
zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len);
}
break;
基本上,这意味着如果它是一个驻留字符串,则不会被复制。但如果不是,它将被复制...那么什么是 interned 字符串,它是什么意思?
在 5.3 中,不存在驻留字符串。所以字符串总是被复制。这真的是唯一的区别......
好吧,在这样的情况下:
$a = "foo";
$b = (string) $a;
在 5.4 中不会复制字符串,但在 5.3 中会复制。
但在这种情况下:
$a = str_repeat("a", 10);
$b = (string) $a;
副本将出现在所有版本中。那是因为在 PHP 中,并不是所有的字符串都是 interned...
让我们在基准测试中尝试一下:http://3v4l.org/HEelW
$a = "foobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisout";
$b = str_repeat("a", 300);
echo "Static Var\n";
testCopy($a);
echo "Dynamic Var\n";
testCopy($b);
function testCopy($var) {
echo memory_get_usage() . "\n";
$var = (string) $var;
echo memory_get_usage() . "\n";
}
结果:
5.4 - 5.5 alpha 1(不包括其他 alpha,因为差异很小,不会造成根本性差异)
Static Var
220152
220200
Dynamic Var
220152
220520
所以静态变量增加了48字节,动态变量增加了368字节。
5.3.11 到 5.3.22:
Static Var
624472
625408
Dynamic Var
624472
624840
静态变量增加了936字节,动态变量增加了368字节。
请注意,在 5.3 中,静态和动态变量都被复制了。所以字符串总是重复的。
但是在带有静态字符串的 5.4 中,只复制了 zval 结构。这意味着被驻留的字符串本身保持不变并且不会被复制......
另一件需要注意的事情是,以上所有内容都没有实际意义。您将变量作为参数传递给函数。然后你在函数内部进行转换。所以写时复制将由您的行触发。所以运行 总是(好吧,在 99.9% 的情况下)会触发变量复制。所以充其量(实习字符串)你在谈论 zval 重复和相关的开销。最坏的情况是,你在谈论字符串重复...
关于php - (string) 'hard-copy' 是字符串吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15139673/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!