DongHao: 09 2009存档
妈:(对姨妈说)刚搬来贵州的时候家在车队住,董昊上小学要走好远的路。有一年冬天上学还不小心踩到水塘里了,他也老实,就这么去上了一天的课,回家发现脚都泡白了。
爸:(吃饭中)什么?
妈:你儿子脚泡白了!
爸:哪只脚?
在遵义家里。
我:(拿起机顶盒上的小鸡毛掸子)咦,这是小时候我挨打的那个鸡毛掸子吗?(看了看)喔,不是,这个小了,是以前那个截短的。
妈:以前那个长,可以掸花瓶上的灰,现在这个短了,只能掸机顶盒上的灰。
我:以后要是再短了,就只能掸杯子里的灰了。以后再短,就只能掸小酒杯里的灰了。
妈:要是再短,就只能掏耳朵里的灰了。
APC可以给php加速,但我在这里不是介绍APC的。
项目开发中我们做了一个php module,里面用到了emalloc和efree,用http_load做了压力一切正常,但装了php-apc以后,httpd进程就一个劲的 core dump。后来查到原因是APC接管了emalloc和efree(具体怎么接管的没来得及查,导致emalloc/efree行为和以前不一致,最后崩 溃。
对于php开发者,APC是透明的;对于php module开发者,APC可就要了命了,先别用emalloc/efree吧。
项目开发中我们做了一个php module,里面用到了emalloc和efree,用http_load做了压力一切正常,但装了php-apc以后,httpd进程就一个劲的 core dump。后来查到原因是APC接管了emalloc和efree(具体怎么接管的没来得及查,导致emalloc/efree行为和以前不一致,最后崩 溃。
对于php开发者,APC是透明的;对于php module开发者,APC可就要了命了,先别用emalloc/efree吧。
声明一个父类Parent,两个子类Son和Daughter继承之,分别将两个子类的创建和实现编译成动态链接库son.so, daughter.so,再通过动态库调用的hello方法:
/* parent.h */
class Parent
{
public:
virtual void hello(void)=0;
virtual void bye(void);
};
/* son.h */
#include "parent.h"
class Son : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* son.cpp */
#include <stdio.h>
#include "son.h"
void Son::hello(void)
{
printf("son\n");
}
static Parent* createPeople(void)
{
return new Son;
}
/* daughter.h */
#include "parent.h"
class Daughter : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* daughter.cpp */
#include <stdio.h>
#include "daughter.h"
void Daughter::hello(void)
{
printf("daughter\n");
}
static Parent* createPeople(void)
{
return new Daughter;
}
/* test.cpp */
#include <stdio.h>
#include <dlfcn.h>
#include "parent.h"
typedef Parent* (Func)(void);
int main(void)
{
void* handle = dlopen("./daughter.so", RTLD_LAZY);
if (handle)
{
Func* f = (Func*)dlsym(handle, "createPeople");
if (f)
{
Parent* p = f();
if (p)
{
p->hello();
}
}
else
{
printf("dlsym:%s\n", dlerror());
}
}
else
{
printf("dlopen:%s\n", dlerror());
}
}
/* parent.h */
class Parent
{
public:
virtual void hello(void)=0;
virtual void bye(void);
};
/* son.h */
#include "parent.h"
class Son : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* son.cpp */
#include <stdio.h>
#include "son.h"
void Son::hello(void)
{
printf("son\n");
}
static Parent* createPeople(void)
{
return new Son;
}
/* daughter.h */
#include "parent.h"
class Daughter : public Parent
{
virtual void hello(void);
};
extern "C" static Parent* createPeople(void);
/* daughter.cpp */
#include <stdio.h>
#include "daughter.h"
void Daughter::hello(void)
{
printf("daughter\n");
}
static Parent* createPeople(void)
{
return new Daughter;
}
/* test.cpp */
#include <stdio.h>
#include <dlfcn.h>
#include "parent.h"
typedef Parent* (Func)(void);
int main(void)
{
void* handle = dlopen("./daughter.so", RTLD_LAZY);
if (handle)
{
Func* f = (Func*)dlsym(handle, "createPeople");
if (f)
{
Parent* p = f();
if (p)
{
p->hello();
}
}
else
{
printf("dlsym:%s\n", dlerror());
}
}
else
{
printf("dlopen:%s\n", dlerror());
}
}
代码如上,现在编译链接:
g++ -shared son.cpp -o son.so -fPIC
g++ -shared daughter.cpp -o daughter.so -fPIC
g++ test.cpp -o test -ldl
g++ -shared daughter.cpp -o daughter.so -fPIC
g++ test.cpp -o test -ldl
运行test,报错:
dlopen:./daughter.so: undefined symbol: _ZTV6Parent
找不到符号Parent,那么nm daughter.so看看是不是没有Parent这个符号,结果看到:
....
U _ZTI6Parent
0000000000100f00 V _ZTI8Daughter
0000000000000ba0 V _ZTS8Daughter
U _ZTV6Parent
0000000000100f00 V _ZTI8Daughter
0000000000000ba0 V _ZTS8Daughter
U _ZTV6Parent
...
居然有两个Parent符号!其中_ZTV6Parent就是dlopen报找不到错误的那个。初遇这个错误让人头晕,哪里蹦出来两个
Parent?仔细检查最后才发现,Parent有两个虚函数,一个是纯虚函数,一个是普通的虚函数,编译器为这两个虚函数分别生成了两个入口表
_ZTI6Parent和_ZTV6Parent,所以最后链接错误。
改正的方法是干脆把两个虚函数都改为纯虚,当然,这只是很多修改方案中的一个。这里最重要的结论是g++对纯虚函数和虚函数会生成两个链接符号入口,知道这一点,再见到这种链接错误就能处理了。