- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
你们中的一些人可能熟悉 PHP 如何在不同的字符串情况下处理内存。
当一个字符串被再次赋值时,它不是“更新的”,而是被克隆的。至少这是我目前的理解。
$a = 'a';
$b = 'b';
$a = $a . $b; // uses sizeof($a)*2 + sizeof($b) bytes
$a .= $b; // uses sizeof($a) + sizeof($b) bytes
在我正在开发的模板引擎中,这意味着巨大的内存消耗。我为一个页面字符串使用了超过 128mb 的内存,实际上,它小于 512kb。这是因为字符串被一遍又一遍地复制。
简单地说,每次我做这样的事情时都会制作这些副本:
$page = str_replace($find, $replace, $page)
一般来说,是否有不创建此克隆的解决方法?
我对它做了一点标记,这将产生相同的输出,但内存消耗完全不同。第一个消耗大量内存,但第二个只消耗实际字符串大小。
$iterations = 100000;
$a = 'a';
$b = 'b';
echo "start peak memory usage " . (memory_get_peak_usage()/1024).'k<br>';
echo "start current memory usage " . (memory_get_usage()/1024).'k<br>';
for($i = 0; $i<$iterations; $i++) {
$a = $a . $b;
}
echo "end peak memory usage " . (memory_get_peak_usage()/1024).'k<br>';
echo "end current memory usage " . (memory_get_usage()/1024).'k<br>';
对比:
$iterations = 100000;
$a = 'a';
$b = 'b';
echo "start peak memory usage " . (memory_get_peak_usage()/1024).'k<br>';
echo "start current memory usage " . (memory_get_usage()/1024).'k<br>';
for($i = 0; $i<$iterations; $i++) {
$a .= $b;
}
echo "end peak memory usage " . (memory_get_peak_usage()/1024).'k<br>';
echo "end current memory usage " . (memory_get_usage()/1024).'k<br>';
那么就模板引擎而言,避免不必要的内存消耗的最佳方法是什么?在开发环境中这不是问题,但在生产环境中它可能成为可扩展性问题.
自然速度也是我关心的问题,所以替代方案应该与这个速度差不多。
最后,我觉得这也跟变量作用域有关。随时纠正我,因为我不是专业人士。我的理解是,当一个函数或方法结束时,PHP 垃圾收集器(?)会“取消设置”变量,但在我的例子中,我们正在处理的 $page
在整个过程中自然存在脚本,因为它是一个类变量,可以访问 $this->page
,因此不能“取消设置”旧实例。
编辑 2014 年 10 月 16 日:为了跟进这个问题,我做了一些测试,并且倾向于提到的将页面分解成多个部分的解决方案。这是一个粗略的结构草图,然后是向下的解释。
class PageObjectX {
$_parent;
__constructor(&$parent) { $this->_parent = $parent; }
/* has a __toString() method, handles how the variable/section is outputted. */
}
class Page {
$_parts;
$_source_parts;
$_variables;
public function __constructor($s) {
$this->_source_parts = preg_split($s, ...);
foreach($this->_source_parts as $part) {
$this->_parts[] = new PageObject($this, ...); }
}
public function ___toString() { return implode('', $this->_parts); }
public function setVariables($k, $v) { $this->_variables[$k] = $v; }
}
我所做的是将模板字符串分解为一个部分数组。常规字符串、变量、从数据库中获取的字符串以及区域/部分。部件数组管理封装在Page类中。该数组具有对象作为元素:PageVariable、PageString、PageRepeatable、PagePlaintext。每个对象都提供一个 toString() 方法,它允许不同类型的部分控制它们的显示方式,并有助于保持类相当小且易于管理。在某种程度上对我来说感觉“干净”。
每个 PageN 类通过对其父类的引用从主类获取数据。因此所有全局变量都设置为页面类,页面类处理对数据库进行单个查询以获取所有已翻译的字符串等。
可重复性可能不是直截了当的。我正在使用 repeatable 来显示列表或可以重复多次的东西,比如新闻项目。内容变了,结构不变。因此,我将以下数组传递给 Page,当可重复名称“news”查找它的数据时,它会获取两个新闻项目的数据。
$regions['news'][0]['news title'] = 'Todays news';
$regions['news'][0]['news desc'] = 'The united nations...';
$regions['news'][1]['news title'] = 'Yesterdays news';
$regions['news'][1]['news desc'] = 'Meanwhile in Afghanistan the rebels...';
如果页面元素没有数据,很容易在 __toString() 中将其排除。这减少了清理模板中未使用部分的需要。
这种方法的整体性能似乎相当不错。在初始比较中,内存消耗约为一半。 2M 与 4M。我希望它在大页面中的比例更好,因为测试页非常简单。与清理占用相当多果汁的字符串版本相比,速度增益非常显着。 0.1 秒与字符串版本的 0.6 秒。
我将发布最终结果的更新,但这就是我目前所拥有的。希望这对那些从谷歌偶然发现这个页面的人有所帮助;)
最佳答案
在您的具体示例中 ($page = str_replace($find, $replace, $page);
) 将无法避免复制 $page
。这适用于所有需要参数按值传递 的函数(无论是否与字符串相关)。然而,PHP 的垃圾回收应该定期释放那些未使用的副本。
如果您仍然遇到过多的内存使用情况,我强烈建议您检查您的代码。确保变量具有明确定义的范围,并且只存储必需的数据。有一些工具可以帮助诊断 PHP 内存使用情况,例如 php-memprof .
此外,我还会确认您使用的是最新可用版本的 PHP 作为垃圾收集 is continuously improved upon .
关于php - 字符串分配中的累积内存使用 : $a = $a . $b vs $a .= $b,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25413472/
我是 Mercurial 的新手,并且不知何故仍处于评估过程中,所以这四个概念对我来说有点困惑。有些被提到等同于 Git 的 Staging/Index 概念,有些甚至比 Git 的 Staging
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 6 个月前关闭。 Improve this ques
任何人都可以给我详细信息吗? 例如? #ID 是属性、特性、选择器还是 anchor ? 默认属性和默认属性是不同的东西吗? 这些都是标签还是元素? 我们将对此说些什么 这个 ..... 还有这些
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 8 年前。 Improve this qu
我有一个由 Javascript 填充的下拉列表。 在决定加载时显示的默认值时,我意识到以下属性显示的值完全相同: innerText innerHTML label text textContent
我可以知道每个 Exec 之间有什么区别吗? , ExecWait , ExecShell , nsExec::Exec , nsExec::ExecToLog, nsExec::ExecToStac
当您处于版本 1 和版本 2 之间时,您会如何维护您的软件? 从我的角度来看,“补丁”、“修补程序”、“维护版本”、“服务包”等术语都很模糊,根据与您交谈的对象不同,定义也不同。 您如何称呼版本之间的
我刚刚发现在 ES6 中有一个新的数学方法:Math.trunc . 我在 MDN article 中阅读了它的描述。 , 听起来像使用 |0 . 此外,>0 , &-1 , ^0也做类似的事情(感谢
我想知道我的 StackPanel 所有项目的高度。 有什么区别: Height - 获取或设置元素的建议高度。 ActualHeight - 获取该元素的渲染高度。 (只读) ExtentHeigh
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 9 年前。 Improve this
我对所有声称以某种方式阻止计算的内置 Mathematica 函数感到困惑:Unevaluated、Defer、Hold ,以及超过 6 个 Hold* 形式。 Mathematica 文档只是单独解
我什至不确定正确的术语,所以让我从我的目标开始:拥有一个简单的应用程序(“Data Doler”),它只会将大量数据从文件读取到内存中,然后提供服务将该数据切片到名为“Data Lapper”的单个多
我刚刚开始在我的项目中使用 Elasticsearch,我想像 sql 关键字一样搜索 '喜欢%' 做。 谁能解释一下 之间的区别通配符 , 前缀 , 查询字符串和 正则表达式 ? 哪个可以搜索最好性
由于我对任何主流浏览器(Firefox、Chrome、Opera)都不太满意,而且我尝试过的不太受欢迎的浏览器(近十几种)都没有,所以我决定 DIY 并制作一个网页我想要最好的浏览器。 主要目标是让它
我知道如何使用 Python 解析页面。我的问题是哪种方法是所有解析技术中最快的,其他方法的速度有多快? 我知道的解析技术有Xpath、DOM、BeautifulSoup,还有使用Python的fin
我试图从正在解析的命令行中找出哪个函数最适合将十进制、十六进制或八进制数转换为 int 最好——在不知道输入的情况下事先。 目标是使用一个函数来识别不同类型的输入并将其分配给它的整数 (int) 值,
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我们需要在我们的网站上显示酒吧、餐馆和剧院等各种场所的元信息(例如,地址、姓名)。 理想情况下,用户会输入地点名称以及邮政编码,我们会提供最接近的匹配项。 人们将哪些 API 用于类似的地理定位目的?
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我正在创建我的第一个 Web 应用程序,我真的很困惑应该使用什么技术。 我的应用程序需要看起来很严肃(像一个应用程序),它不需要很多色彩缤纷的图形界面。它只需要一个工具栏、一个标签栏、一个拆分面板(最
我是一名优秀的程序员,十分优秀!