我们经常采用如下方式定义单列:
class Singleton {
private static $instance = NULL;
/** 不容许直接调用构造函数 */
private function __construct() {
}
/** 不容许深度复制 */
private function __clone() {
}
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
很多人都会记得对深度copy的保护, 但, 其实我们却疏忽了一点…
首先让我们看一个问题: 如下代码的输出,
var_dump(memory_get_usage()); $a = "laruence"; var_dump(memory_get_usage()); unset($a); var_dump(memory_get_usage());
输出(在我的个人电脑上, 可能会因为系统,PHP版本,载入的扩展不同而不同):
int(90440) int(90640) int(90472)
注意到 90472-90440=32, 于是就有了各种的结论, 有的人说PHP的unset并不真正释放内存, 有的说, PHP的unset只是在释放大变量(大量字符串, 大数组)的时候才会真正free内存, 更有人说, 在PHP层面讨论内存是没有意义的.
那么, 到底unset会不会释放内存? 这32个字节跑哪里去了?
你也许注意到过, 在PHP中使用ECHO输出大段字符串的时候, 执行时间会明显的长, 也就会有朋友认为PHP的ECHO性能很差.
我在之前的文章中, 已经解释过了原因, 也希望能纠正”PHP的ECHO性能差”的这个误会.
然而之前的文章, 也仅仅是给出了原因, 并没有介绍如何避免这个问题, 在今天公司内的某个产品线(Apache with PHP)发现了一个问题, 有用户在短时间内大量发起下载请求, 导致http连接数和数据库连接数剧增,
而数据库连接数剧增的原因是因为数据库的连接是单列模式, 一直到请求处理结束, 才会释放数据库链接. 这样就有了一个问题, 如果请求处理时间过长, 就会造成大量的数据库链接存在.
而这个用户的网速很慢,, 下载时间很长~, 这也就意味着, ECHO的”性能”很差~
这也就引出了今天我要谈的这个问题, 如何让ECHO变快, 让PHP的请求处理过程, 尽快结束…
一个同事forward过来一个, 公司某产品线遇到的一个低概率, 但长时间出现了几次的Core的bt信息, 找我帮忙分析下原因.
bt栈如下(路径信息以*代替):
#0 0x00000000004a75e5 in _zend_mm_alloc_int (heap=0xd61260, size=79)
at /*/php-5.2.6/Zend/zend_alloc.c:1879
#1 0x000000000048d3cd in vspprintf (pbuf=0x7fbffe9cd8, max_len=1024, format=Variable "format" is not available.
)
at /*/php-5.2.6/main/spprintf.c:224
#2 0x0000000000489747 in php_error_cb (type=1, error_filename=0x2a9a787ee8 "/*/application/helpers/util.php",
error_lineno=1149, format=Variable "format" is not available.
) at /*/php-5.2.6/main/main.c:799
#3 0x000000000061db35 in soap_error_handler (error_num=1,
error_filename=0x2a9a787ee8 "/*/application/helpers/util.php", error_lineno=1149,
format=0x7b9cb8 "Maximum execution time of %d second%s exceeded", args=0x7fbffea3b0)
at /*/php-5.2.6/ext/soap/soap.c:2178
#4 0x00000000004c2576 in zend_error (type=1, format=0x7b9cb8 "Maximum execution time of %d second%s exceeded")
at /*/php-5.2.6/Zend/zend.c:976
#5 <signal handler called>
#6 0x00000000004a720f in _zend_mm_free_int (heap=0xd61260, p=Variable "p" is not available.
) at /*/php-5.2.6/Zend/zend_alloc.c:844
...以下省略
在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步,
1. 发送一个请求, 包含一个Expect:100-continue, 询问Server使用愿意接受数据 2. 接收到Server返回的100-continue应答以后, 才把数据POST给Server
首先感谢DiaHosting给我赞助了一个免费的VPS.
今天我终于把blog(WordPress)迁移到了新的VPS上, 由于环境的不一致(原来是Apache+mod_php, 现在是lighttpd+php_cgi), 中间出现不少问题, 但都没啥可说的.
一直到遇到如下这个问题:
Compilation failed: support for \P, \p, and \X has not been compiled at offset 16 in /***/search-everything.php on line 802
比如, 我提供一个查询服务, 用户可以提交一个人的名字和年龄做为查询条件.
假设我要查询一个名字叫做”laruence”, 年龄是27的人, 我认为这个人的定义的查询token可以写做:
laruence=27
不幸的是, 当这样的一个token做为query string提交给服务器的处理脚本的时候, 你就会发现, 诶,,我不知道用户名是什么,,,
那么能否在PHP中获取到一个变量的名字呢?
一般很少有用PHP做服务的, 但是如果你的已有业务逻辑都是PHP实现的, 而现在却需要基于已有的业务逻辑提供一套Socket服务, 怎么办?
当然, 解决方法很多, 但最简单的办法, 还是直接使用PHP做Socket服务.
而这样做要解决的问题有很多, 主要要解决的问题有如下几个:
1. 作为后台服务,需要常驻后台运行, 那么丁点的内存泄露都是不能接受的. 2. 作为后台服务,畸形数据导致进程异常退出, 也是不可接受的. 3. 作为后台服务, 要能做到graceful restart. 4. 作为后台服务, 对资源的使用必须在可接受的范围以内.
最近,我就基于PHP写一个简单的提供Socket服务的框架. 取其名为Mpass(Multi-Processes Socket Server).
PHP的命名空间, 实现的还真是简单.
当你有如下代码:
<?php
namespace Yaf;
class Application {
}
其实就相当于, 你声明了一个名字为A\B的类, 当然, 你不能直接这么申明(只是不能在PHP脚本中这么申明).
同事发现一个在使用set_error_handler的时候, 能100%重现的core, 提炼后的重现代码如下(环境必须不能访问internet):
<?php
function err_handler(){
exit;
return true;
}
set_error_handler('err_handler');
$client = file_get_contents("http://www.laruence.com/ServiceNoWse.asmx?WSDL");
这段代码, 放在webServer中, 第一次访问不会有事, 第二第三次的时候就会出core.