最近遇到的问题整理(linux下创建线程内存泄漏,php的json_encode等)
这次还是把遇到的几个问题整理一下,希望再遇到的同学能轻松解决。另外最近博客的feeds延迟更新的原因也会一起说明一下。
1.linux下创建线程导致内存泄漏
今天在外网发布了一个server之后,用top发现virt的使用量一直在涨,而且一次涨8m。于是可以断定有内存泄漏了,经过排查,最终确定原因出在多线程的问题上:
代码如下:
1 2 3 4 5 6 | pthread_t thread_id; int ret=pthread_create(&thread_id, NULL, flush_thread_work, (void*)&m_sql_client); if(ret!=0){ APPSCORE_ERROR("Thread creation failed:%d",ret); return ret; } |
在flush_thread_work函数内部:
1 2 3 4 5 | void* flush_thread_work(void* args) { //....do something return NULL; } |
代码中启动了一个线程之后,主进程就继续执行,任由新线程自生自灭了(没有调用thread_join),而主进程每隔一段时间就会拉起这样一个线程来做一些数据落地的事情。
这样的写法实际上是会造成内存泄漏的.
Linux man page 里有已经说明了这个问题:
When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore, pthread_join must be called once for each joinable thread created to avoid memory leaks.
也就说线程执行完后如果不join的话,线程的资源会一直得不到释放而导致内存泄漏!
解决方法有两种:
a.在线程执行的函数内手工释放
1 2 3 4 5 6 | void* flush_thread_work(void* args) { //....do something pthread_detach(pthread_self()); return NULL; } |
b.在线程启动时,设置线程的PTHREAD_CREATE_DETACHED属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | pthread_attr_t attr; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); int ret=pthread_create(&thread_id, &attr, flush_thread_work, (void*)&m_sql_client); if(ret!=0){ //记住attr也要析构,否则又是一个内存泄漏 pthread_attr_destroy (&attr); APPSCORE_ERROR("Thread creation failed:%d",ret); return ret; } //记住attr也要析构,否则又是一个内存泄漏 pthread_attr_destroy (&attr); |
这样问题就可以解决了。
参考资料:
解决了一个隐蔽的内存泄漏——pthread_create后没有detach导致内存持续增长
2.php的json_encode函数问题
在公司做了一个应用,是php与c++进行网络交互,所以选择了json这种比较通用的序列化格式,然而却遇到了比较奇怪的问题。
先来看如下代码(php):
1 2 3 4 5 | $objs = array(); $objs[1] = 'a'; $objs[2] = 'b'; $objs[4] = 'd'; echo json_encode($objs)."\n"; |
输出的结果如下:
{"0":"a","1":"b","3":"d"}这样是正常的,用jsoncpp也可以正确的解析出来,php自动将$objs当作一个关联数组来生成json数据了。
然而当把代码换成如下:
1 2 3 4 5 6 | $objs = array(); $objs[0] = 'a'; $objs[1] = 'b'; $objs[2] = 'c'; $objs[3] = 'd'; echo json_encode($objs)."\n"; |
则输出结果如下:
["a","b","c","d"]
jsoncpp按照之前的解析方法是解析不出来的~
其实对php来说,这也是合理的,问题在于在php里面普通数组和关联数组都是array,而对c++来说,却存在vector和map之分,所以如果还是想要json_encode生成关联数组的格式,那么需要这样写:
1 2 3 4 5 6 | $objs = array(); $objs[0] = 'a'; $objs[1] = 'b'; $objs[2] = 'c'; $objs[3] = 'd'; echo json_encode((object)$objs)."\n"; |
结果如下:
{"0":"a","1":"b","2":"c","3":"d"}3.本博feed延迟不更新的原因
之前由于对feedsky的feed更新十分不满,所以参考网上的做法,建立了一个feed.vimer.cn,而本博所在的域名空间会自动根据域名创建一个子目录 - feed,修改这个目录下的.htaccess文件如下:
1 2 3 4 5 | <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule . http://feed.feedsky.com/vimer [L] </IfModule> |
那么当访问 feed.vimer.cn 时,会自动跳转到 http://feed.feedsky.com/vimer。
然而我忽略了一个问题,那就是wordpress默认的feed链接是 http://vimer.cn/feed/rss2,而/feed/rss2会被解析成子目录,从而自动跳转到 http://feed.feedsky.com/vimer ,所以feedsky就会不停的读 http://feed.feedsky.com/vimer 这个链接的feed,当然不会有任何新数据。。
所以最后还是把这种方式废弃掉了,看来真是冤枉了feedsky呀~~~
OK,最近的总结就这么多~
原创文章,版权所有。转载请注明:转载自Vimer的程序世界 [ http://www.vimer.cn ]
本文链接地址: http://www.vimer.cn/?p=2170
其实php遵循了json的标准
第一种的array,在json看来是个无序的键值对,所以会生成一个object;而第二种写法是有序的,所以会生成一个json标准的array,当然显示转换成object也是可以的。
参考:http://json.org/json-zh.html
[回复]
怎么没想着用FeedBurner来烧Feed?
[回复]
Dante 回复:
四月 18th, 2011 at 12:36 上午
天朝,你懂得。。
[回复]
zach 回复:
四月 25th, 2011 at 8:16 下午
Google Reader里直接添加无视天朝。
[回复]
多个pthread可以共用一个pthread_attr。
[回复]
Dante 回复:
四月 18th, 2011 at 12:36 上午
受教了~,多谢~
[回复]
善于整理,不错不错。是一个好习惯,呵呵,向博主学习。
[回复]
json_encode带可选参数JSON_FORCE_OBJECT可以强制转为object形式
[回复]
Dante 回复:
五月 9th, 2011 at 11:09 上午
呃,提示我只能传入一个参数。。
[回复]
流年 回复:
五月 12th, 2011 at 11:04 下午
版本的原因?
http://cn.php.net/manual/en/function.json-encode.php 中的函数版本(PHP 5 >= 5.2.0, PECL json >= 1.2.0)
[回复]
[...] http://www.vimer.cn/2011/04/%E6%9C%80%E8…6%BC%8Fphp%E7%9A%84json_encode.html 最近遇到的问题整理(linux下创建线程内存泄漏,php的json_encode等) [...]
写的很好. http://www.7004054.com 期待您的回访.
[回复]
Posix线程琐碎难用,写出来的code也是error proned,比较建议将线程相关的API封装一下进程管理。
[回复]
Heartwork 回复:
六月 1st, 2011 at 10:46 下午
进行管理
[回复]
pthread_detach(pthread_self());
pthread_self()是返回当前线程id
pthread_detach是设置为分离线程。
和“销毁”的语义差别太大了吧。
而且根本不需要放在函数最后。
[回复]
Dante 回复:
一月 15th, 2012 at 6:42 下午
呃,文章有点久了,但我确实通篇没见我写过销毁这两个字?
[回复]