磨砺技术珠矶,践行数据之道,追求卓越价值
回到上一级页面: PostgreSQL集群方案相关索引页 回到顶级页面:PostgreSQL索引页
[作者 高健@博客园 luckyjackgao@gmail.com]
接上文,继续对pgpool-II3.1的内存泄漏进行分析。
情形A extract_string 调用 strdup
==27927== 3 bytes in 1 blocks are possibly lost in loss record 3 of 100
==27927== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)
==27927== by 0x3C51E798C1: strdup (in /lib64/libc-2.5.so)
==27927== by 0x40C9C4: extract_string (pool_config.l:2065)
==27927== by 0x410D52: pool_get_config (pool_config.l:1756)
==27927== by 0x4066B5: main (main.c:320)
==27927==
从上述log可知, 调用关系如下:
main->pool_get_config -> extract_string -> strdup->malloc
以下是各个函数的主要相关逻辑:
pool_get_config函数(中间省略了很多):
复制代码
int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context){
......
#define PARSE_ERROR()
pool_error("pool_config: parse error at line %d '%s'", Lineno, yytext)
/* open config file */
fd = fopen(confpath, "r");
if (!fd){
fprintf(stderr, "pool_config: could not open configuration file (%s)\n",
POOL_CONF_FILE_NAME);
fprintf(stderr, "pool_config: using default values...\n");
return 0;
}
yyin = fd;
Lineno = 1;
for(;;)
{
token = yylex();
if (token == 0){
break;
}
if (token == POOL_PARSE_ERROR){
PARSE_ERROR();
fclose(fd);
return(-1);
}
if (token == POOL_EOL)
continue;
if (token != POOL_KEY){
PARSE_ERROR();
fclose(fd);
return(-1);
}
……
if (!strcmp(key, "allow_inet_domain_socket") &&
CHECK_CONTEXT(INIT_CONFIG, context)){
……
}
else if (!strcmp(key, "listen_addresses") &&
CHECK_CONTEXT(INIT_CONFIG, context)){
char *str;
if (token != POOL_STRING && token != POOL_UNQUOTED_STRING &&
token != POOL_KEY){
PARSE_ERROR();
fclose(fd);
return(-1);
}
str = extract_string(yytext, token);
if (str == NULL){
fclose(fd);
return(-1);
}
pool_config->listen_addresses = str;
}
……
else if (!strncmp(key, "backend_hostname", 16) &&
CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
mypid == getpid())
/* this parameter must be modified by parent pid */
{
int slot;
char *str;
slot = atoi(key + 16);
if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
{
pool_error("pool_config:
backend number %s for backend_hostname out of range", key);
fclose(fd);
return(-1);
}
str = extract_string(yytext, token);
if (str == NULL){
fclose(fd);
return(-1);
}
if (context == INIT_CONFIG || (context == RELOAD_CONFIG &&
BACKEND_INFO(slot).backend_status == CON_UNUSED))
strncpy(BACKEND_INFO(slot).backend_hostname, str,
MAX_DB_HOST_NAMELEN);
}
……
else if (!strcmp(key, "relcache_expire") &&
CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context)){
int v = atoi(yytext);
if (token != POOL_INTEGER || v < 0){
pool_error("pool_config: %s
must be equal or higher than 0 numeric value", key); fclose(fd);
return(-1);
}
pool_config->relcache_expire = v;
}
}
fclose(fd);
……
return 0;
}
复制代码
extract_string 函数:
复制代码
static char *extract_string(char *value, POOL_TOKEN token){
char *ret;
ret = strdup(value);
if (!ret){
pool_error("extract_string: out of memory");
return NULL;
}
if (token == POOL_STRING){
ret[strlen(ret)-1] = '\0';
return (ret+1);
}
return ret;
}
复制代码
strdup 是C 语言的标准函数, 是字符串复制。
其内部调用了 malloc ,在运行结束的时候,应当释放。
但是!
由于其 是在 pool_config.c 的 pool_get_config 中被调用,
这个函数 是要实现 把配置文件中的各项内容读取出来。
配置文件项内容的地址,就存储在 strdup 返回的 指针里面。
在pgpool 运行结束以前, 都是需要能随时访问 配置文件向内容的。
所以,在pgpool运行结束以前,都是不能随意 释放 strdup返回 值的。
至于运行结束的那一刻 是否 有代码专门来释放了,前面我们的分析已经说过,不在我们的讨论范围内。
[作者 高健@博客园 luckyjackgao@gmail.com]
回到上一级页面: PostgreSQL集群方案相关索引页 回到顶级页面:PostgreSQL索引页
磨砺技术珠矶,践行数据之道,追求卓越价值
本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2012/08/21/2649037.html,如需转载请自行联系原作者