W3C DOM – {setAttribute()}

setAttribute(string name, string value):增加一个指定名称和值的新属性,或者把一个现有的属性设定为指定的值。

1、setAttribute()的差异
我们经常需要在JavaScript中给Element动态添加各种属性,这可以通过使用setAttribute()来实现,这就涉及到了浏览器的兼容性问题。

var bar = document.getElementById("foo");
bar.setAttribute("onclick", "javascript:alert('This is a test!');");

这里利用setAttribute指定Element的onclick属性,简单,很好理解。但是IE不支持,IE并不是不支持setAttribute这个函数,而是不支持用setAttribute设置某些属性,例如对象属性、集合属性、事件属性,也就是说用setAttribute设置style和onclick 这些属性在IE中是行不通的。为达到兼容各种浏览器的效果,可以用点符号法来设置Element的对象属性、集合属性和事件属性。

document.getElementById("foo").className = "fruit";
document.getElementById("foo").style.cssText = "color: #00f;";
document.getElementById("foo").style.color = "#00f";
document.getElementById("foo").onclick= function () { alert("This is a test!"); }

2、关于class和className
class 属性在W3C DOM中扮演着很重要的角色,但由于浏览器差异性仍然存在。使用setAttribute(“class”, vName)语句动态设置element的class属性在firefox中是行的通的,在IE中却不行。因为使用IE内核的浏览器不认识 “class”,要改用”className”;同样,firefox 也不认识”className”。所以常用的方法是二者兼备:

element.setAttribute("class", vName);
element.setAttribute("className", vName);    // for IE

3、cellspacing和cellpadding
虽然在CSS中存在与cellpadding和cellspacing这两个属性等价的样式属性padding和 border-spacing。然而,浏览器对这些样式属性支持的不一致,有时仍会使用cellpadding和 cellspacing来调整表格的间距。不过,在firefox中有效的setAttribute(“cellpadding”, value)到了IE下就不行了,必须改成cellPadding才可以(注意:p大写)。幸好firefox也支持setAttribute(“cellPadding”, value)。所以二者兼容的代码是:

element.setAttribute("cellSpacing", value);
element.setAttribute("cellPadding", value);

PHP对象相互引用的内存溢出

使用脚本语言最大的好处之一就是可利用其拥有的自动垃圾回收机制(释放内存)。你不需要在使用完变量后做任何释放内存的处理,PHP会帮你完成。

当然,我们可以按自己的意愿调用 unset() 函数来释放内存,但通常不需要这么做。

不过在PHP里,至少有一种情况内存不会得到自动释放,即便是手动调用 unset()。详情可考:http://bugs.php.net/bug.php?id=33595。

问题症状
如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 unset() 不会释放在子对象中引用父对象的内存(即便父对象被垃圾回收,也不行)。

有些糊涂了?我们来看下面的这段代码:

bar = new Bar($this);
    }
}

class Bar {
function __construct($foo = null)
    {
        $this->foo = $foo;
    }
}

while (true) {
    $foo = new Foo();
    unset($foo);
    echo number_format(memory_get_usage()) . "\n";
}
?>

运行这段代码,你会看到内存使用率越来越高越来越高,直到用光光。

…33,551,61633,551,97633,552,33633,552,696PHP Fatal error: Allowed memory size of 33554432 bytes exhausted(tried to allocate 16 bytes) in memleak.php on line 17对大部分PHP程序员来讲这种情况不算是什么问题。

可如果你在一个长期运行的代码中使用到了一大堆相互引用的对象,尤其是在对象相对较大的情况下,内存会迅速地消耗殆尽。

Userland解决方案
虽然有些乏味、不优雅,但之前提到的 bugs.php.net 链接中提供了一个解决方案。

这个方案在释放对象前使用一个 destructor 方法以达到目的。Destructor 方法可将所有内部的父对象引用全部清除,也就是说可以将这部分本来会溢出的内存释放掉。

以下是“修复后”的代码:

bar = new Bar($this);
    }
    function __destruct()
    {
        unset($this->bar);
    }
}

class Bar {
    function __construct($foo = null)
    {
        $this->foo = $foo;
    }
}

while (true) {
    $foo = new Foo();
    $foo->__destruct();
    unset($foo);
    echo number_format(memory_get_usage()) . "\n";
}
?>

注意那个新增的 Foo::__destruct()方法,以及在释放对象前对 $foo->__destruct() 的调用。现在这段代码解决了内存使用率一直增加的问题,这么一来,代码就可以很好的工作了。

PHP内核解决方案?
为什么会有内存溢出的发生?我对PHP内核方面的研究并不精通,但可以确定的是此问题与引用计数有关系。

在 $bar 中引用 $foo 的引用计数不会因为父对象 $foo 被释放而递减,这时PHP认为你仍需要 $foo 对象,也就不会释放这部分的内存……大概是这样。

这里确实可以看出我的无知,但大体意思是:一个引用计数没有递减,所以一些内存永远得不到释放。

在前面提到的 bugs.php.net 链接中我看到修改垃圾回收的过程将会牺牲极大的性能,因为我对引用计数了解不多,所以我认为这是真的。

与其改变垃圾回收的过程,为什么不用 unset() 对内部对象做释放的工作呢?(或者在释放对象的时候调用 __destruct()?)

也许PHP内核开发者可以在此或其他地方,对这种垃圾回收处理机制做出修改。

更新:Martin Fjordvald 在评论中提到了一个由 David Wang 为垃圾回收所写的补丁(其实它看起来更像“一整块布”——非常巨大。详情参见此邮件结尾的CVS导出信息。)确实存在(一封邮件),并受到了PHP内核开发成员的关注。问题是这个补丁要不要放到PHP5.3中并未得到太多支持 。我觉得一个不错的折中方案就是在 unset() 函数中调用对象中的 __destruct() 方法;

nginx freebsd 官方网站优化

OS & Hardware
FreeBSD 7.1
AMD64, dual-core CPU
4GB RAM
Purpose
Web server & reverse proxy
Load description
45K inactive keep-alive connections
HTTP request is about 5,000 req/s, mostly small static files, all are cached by VM
System config
/boot/loader.conf:

vm.kmem_size=1844M
kern.maxbcache=64M
kern.ipc.maxpipekva=4M

/etc/sysctl.conf:

kern.ipc.nmbjumbop=192000
kern.ipc.nmbclusters=229376
kern.ipc.maxsockets=204800
net.inet.tcp.maxtcptw=163840
kern.maxfiles=204800

kern.ipc.somaxconn=4096

Retrieved from “http://wiki.nginx.org/FreeBSDOptimizations”