zoukankan      html  css  js  c++  java
  • pgpoolII3.1 的内存泄漏(七)

    磨砺技术珠矶,践行数据之道,追求卓越价值
    回到上一级页面: PostgreSQL集群方案相关索引页     回到顶级页面:PostgreSQL索引页
    [作者 高健@博客园  luckyjackgao@gmail.com]

    接上文,

    情形D extract_string_tokens 调用 malloc

    ==27927== 24,630 (24,576 direct, 54 indirect) bytes in 3 blocks are definitely lost in loss record 100 of 100
    ==27927== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)
    ==27927== by 0x40C8FC: extract_string_tokens (pool_config.l:2191)
    ==27927== by 0x41177B: pool_get_config (pool_config.l:1657)
    ==27927== by 0x4066B5: main (main.c:320)
    ==27927==

    从上述log可知, 调用关系如下:

    main->pool_get_config -> extract_string_tokens -> malloc

    以下是各个函数的主要相关逻辑:

    pool_get_config 函数:

    int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context)                                                
    {                                                
        FILE *fd;                                            
        int token;                                            
        char key[1024];                                            
        double total_weight;                                            
        int i;                                            
        bool log_destination_changed = false; 
                                                    
        #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, "reset_query_list") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_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->reset_query_list = extract_string_tokens(str, ";", pool_config->num_reset_queries); if (pool_config->reset_query_list == NULL) { fclose(fd); return(-1); } } else if (!strcmp(key, "white_function_list") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_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->white_function_list = extract_string_tokens(str, ",",
    &pool_config->num_white_function_list); if (pool_config->white_function_list == NULL) { fclose(fd); return(-1); } for (i=0;i<pool_config->num_white_function_list;i++) { add_regex_pattern("white_function_list",
    pool_config->white_function_list[i]); } } else if (!strcmp(key, "black_function_list") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_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->black_function_list = extract_string_tokens(str, ",",
    &pool_config->num_black_function_list); if (pool_config->black_function_list == NULL) { fclose(fd); return(-1); } for (i=0;i<pool_config->num_black_function_list;i++) { add_regex_pattern("black_function_list",
    pool_config->black_function_list[i]); } } …… else if (!strncmp(key, "backend_flag", 12) && CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && mypid == getpid())
    /* this parameter must be modified by parent pid */ { …… flags = extract_string_tokens(str, "|", &n); if (!flags || n < 0) { pool_debug("pool_config: unable to get backend flags"); fclose(fd); return(-1); } for (i=0;i<n;i++) { if (!strcmp(flags[i], "ALLOW_TO_FAILOVER")) { if (disallow_to_failover_is_specified) { pool_error("pool_config: cannot set ALLOW_TO_FAILOVER
    and DISALLOW_TO_FAILOVER at the same time
    "); fclose(fd); return(-1); } flag &= ~POOL_FAILOVER; allow_to_failover_is_specified = true; pool_debug("pool_config: allow_to_failover on"); } else if (!strcmp(flags[i], "DISALLOW_TO_FAILOVER")) { if (allow_to_failover_is_specified) { pool_error("pool_config: cannot set ALLOW_TO_FAILOVER
    and DISALLOW_TO_FAILOVER at the same time
    "); fclose(fd); return(-1); } flag |= POOL_FAILOVER; disallow_to_failover_is_specified = true; pool_debug("pool_config: disallow_to_failover on"); } else { pool_error("pool_config: invalid backend flag:%s", flags[i]); } } …… } …… } fclose(fd); …… return 0; }

    extract_string_tokens 函数:

    /*                                        
     * Extract tokens separated by delimi from str. Return value is an 
     * array of pointers to malloced strings. number of tokens is set to 
     * n; note that str will be destroyed by strtok(). 
     */                                        
    #define MAXTOKENS 1024                                        
    static char **extract_string_tokens(char *str, char *delimi, int *n)                                        
    {                                        
        char *token;                                    
        static char **tokens;                                    
                                            
        *n = 0;                                    
                                            
        tokens = malloc(MAXTOKENS*sizeof(char *));                                    
        if (tokens == NULL)                                    
        {                                    
            pool_error("extract_string_tokens: out of memory");                                
            return NULL;                                
        }                                    
                                            
        for (token = strtok(str, delimi); token != NULL && *n < MAXTOKENS; token = strtok(NULL, delimi))                                    
        {                                    
            tokens[*n] = strdup(token);                                
            if (tokens[*n] == NULL)                                
            {                                
                pool_error("extract_string_tokens: out of memory");                            
                return NULL;                            
            }                                
            pool_debug("extract_string_tokens: token: %s", tokens[*n]);                                
            (*n)++;                                
        }                                    
        return tokens;                                    
    }                                        
                                            

    和情形 A 有些类似,在 extract_string_tokens函数中,调用了 malloc开了内存

    但是!  
    由于其 是在 pool_config.c 的 pool_get_config 中被调用,
    这个函数 是要实现 把配置文件中的各项内容读取出来。
    配置文件项内容的地址,就存储在 返回的 指针里面。

    在pgpool 运行结束以前, 都是需要能随时访问 配置文件向内容的。
    所以,在pgpool运行结束以前,都是不能随意 释放 。

    至于运行结束的那一刻 是否 有代码专门来释放了,前面我们的分析已经说过,不在我们的讨论范围内。

    其实,如果略作展开,看pgpool运行结束的时候,是否有可能释放的问题:
    下面的这种是根本没有可能得到释放的了:

    flags = extract_string_tokens(str, "|", &n);

    这是因为 flags根本不是返回的值

    我们调用了
    pool_get_config 函数,pool_get_config函数中调用 extract_string_tokens ,
    此后, 根本无从 保存 flags 指针。所以这段内存,在pgpool运行结束后,只能说是 “丢了"。

    [作者 高健@博客园  luckyjackgao@gmail.com]
    回到上一级页面: PostgreSQL集群方案相关索引页     回到顶级页面:PostgreSQL索引页
    磨砺技术珠矶,践行数据之道,追求卓越价值

  • 相关阅读:
    将博客搬至CSDN
    ActiveMQ 的可持久化(六)
    ActiveMQ之协议(五)
    ActiveMQ与Spring / SpringBoot 整合(四)
    ActiveMQ之JMS及保证消息的可靠性<持久化、事务、签收>(三)
    ActiveMQ部署和代码尝试(二)
    ActiveMQ初步安装使用(一)
    Redis之哨兵机制(五)
    Redis主从复制(读写分离)(四)
    Redis持久化(三)
  • 原文地址:https://www.cnblogs.com/gaojian/p/2649124.html
Copyright © 2011-2022 走看看