我意识到对这个问题的下意识反应是"你不要.",但是听我说.
基本上我在SQL上的活动记录系统上运行,并且为了防止同一数据库行的重复对象,我在工厂中为每个当前加载的对象保留一个"数组"(使用自动增量'id'作为键).
问题是,当我尝试在奇怪的场合通过这个系统处理90,000多行时,PHP会遇到内存问题.这很容易通过每隔几百行运行一次垃圾收集来解决,但不幸的是,由于工厂存储了每个对象的副本 - PHP的垃圾收集不会释放任何这些节点.
我能想到的唯一解决方案是检查存储在工厂中的对象的引用计数是否等于1(即没有引用该类),如果是这样,则释放它们.这可以解决我的问题,但PHP没有引用计数方法?(除了debug_zval_dump,但那几乎不可用).
Sean的debug_zval_dump函数看起来好像会告诉你refcount,但实际上,从长远来看,refcount对你没有帮助.
您应该考虑使用有界数组作为缓存; 这样的事情:
<?php
class object_cache {
var $objs = array();
var $max_objs = 1024; // adjust to fit your use case
function add($obj) {
$key = $obj->getKey();
// remove it from its old position
unset($this->objs[$key]);
// If the cache is full, retire the eldest from the front
if (count($this->objs) > $this->max_objs) {
$dead = array_shift($this->objs);
// commit any pending changes to db/disk
$dead->flushToStorage();
}
// (re-)add this item to the end
$this->objs[$key] = $obj;
}
function get($key) {
if (isset($this->objs[$key])) {
$obj = $this->objs[$key];
// promote to most-recently-used
unset($this->objs[$key]);
$this->objs[$key] = $obj;
return $obj;
}
// Not cached; go and get it
$obj = $this->loadFromStorage($key);
if ($obj) {
$this->objs[$key] = $obj;
}
return $obj;
}
}
Run Code Online (Sandbox Code Playgroud)
这里,getKey()返回您要存储的对象的一些唯一ID.这依赖于PHP记住插入其哈希表的顺序这一事实; 每次添加新元素时,它都会在逻辑上附加到数组中.
get()函数确保您访问的对象保留在数组的末尾,因此数组的前面将是最近最少使用的元素,这是我们在决定时要处理的对象空间很小; array_shift()为我们这样做.
此方法也称为最近使用的或MRU缓存,因为它缓存最近使用的项目.我们的想法是,您更有可能访问最近访问过的项目,因此您可以保留它们.
你得到的是控制你保留的最大对象数量的能力,你不必在有意识地难以访问的php实现细节上找到它.
看起来最好的答案仍然是获取引用计数,尽管debug_zval_dump和ob_start太难看了,我的应用程序中包含了hack.
相反,我编写了一个带有refcount()函数的简单PHP模块,可从以下网址获得:http://github.com/qix/php_refcount
| 归档时间: |
|
| 查看次数: |
3593 次 |
| 最近记录: |