码迷,mamicode.com
首页 > 其他好文 > 详细

一个内存泄露问题的分析和处理(一)

时间:2014-05-09 10:09:26      阅读:1116      评论:0      收藏:0      [点我收藏+]

标签:des   blog   class   code   ext   color   

        关于内存泄露的问题,之前遇到过一次,当时的应用场景是这样的:

        生产环境的oracle分为两个RAC,需要做单点故障的测试,就把其中的一个RAC给停掉了,看看程序能否连接到另外一个RAC。有一个程序在这种情况下,出现了内存泄露的情况,内存疯狂增长,最终内存耗尽,导致业务主机宕机。后来派出框架部门和业务部门一起来分析,最终得出的结论是由于数据库连接没有释放导致数据处理时,一直在使用一个失效的连接,所以不断抛出OTL的异常。

        大概的逻辑是这样的,程序启动时,会对每一个数据库的做一个连接池,当需要数据库连接时,就从连接池中获取一个数据库连接即可,正常情况下,连接可用,可以直接做数据处理,当数据库发生异常时,比如说某一个RAC宕机时,数据库连接已经失效,此时需要连接池把这个连接回收掉,回收连接有两个条件,1、连接没有被占用;2、连接已经失效。如果程序不去主动把连接释放,连接会一直处于被占用的状态,导致这个连接一直存在在连接池中,但是连接确实是失效的,下次去连接池申请连接时,申请到的,还是这个错误的连接,就会出现不断去尝试执行SQL,但是却不断失败的情况。当时一位数据库接口开发人员分析说当数据库宕机的时候,不断的尝试,OCI会有内存泄露的情况,由于当时没什么经验,也就相信了。后来就修改了业务代码,在异常的情况下,把数据库连接释放掉,连接池会把数据库连接回收掉,这个问题也就“愉快“的解决了。

        问题“愉快”解决的原因是多方面的:

   第一:领导希望能看到问题尽快解决,不管解决的方式是怎样的;

        第二:框架部门的技术是比较强大的,作为业务部门,我们选择相信框架的解释;

        第二:单点故障测试不是每天都进行的,如何对我们分析出的问题原因做验证,是一个复杂的问题。

        据我所知,后来客户也没在做过单点故障的测试,所以说这个问题,其实只是做了修改,但是却没有验证之前的分析和修改。

        最近由于客户要上一个新的版本的库,需要进行全量的测试,这个程序再次被测试到,这次的场景发生了变化,是这样的:

        客户在测试时,人工的把数据库给停掉了,程序在另一台主机,程序都没有停,最后发现这个程序占用的内存达到了260多G,一下子又把这个问题暴漏了出来。其实一开始听到这个问题时,我主观的想到了是OCI的问题,因为数据库已经停掉,不断的去尝试,导致OCI内存泄露,最终内存涨到了260多个G。这样分析似乎没有”问题“,可是却有一个最大的问题,因为当时给出这个结论的框架部门的员工已经离职,如何让客户信服。我决定自己测试下这个问题。我写了一个测试的程序,来测试OTL的问题的方法,主要分为几种Case:

  1、数据库主机不存在,不断尝试连接数据库

  2、数据库主机正常,oracle服务启动,不断尝试连接数据库

  3、数据库主机正常,oracle服务正常,当连接上后,把数据库服务停掉,然后程序不释放连接,不断的使用旧的连接去尝试执行SQL

  代码如下:

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
using namespace std;
 
#define OTL_ORA10G  //不可缺少
#include "otlv4.h" //注意OTL头文件位置
 
otl_connect db;
string strMonitorSql = "select 1 from dual";
 
int main()
{
    otl_connect::otl_initialize(); 
 
    cout << "try to connect oracle" << endl;
 
    while(!db.connected)
    {
 
        try
        {
            db.rlogon("ad/ad@192.168.80.13:1521/dev");
        }
        catch(otl_exception& p)
        
            cerr<<p.msg<<endl; 
            cerr<<p.stm_text<<endl; 
            cerr<<p.sqlstate<<endl; 
            cerr<<p.var_info<<endl; 
            cout<<"Connected to Database fail "<<endl;
            continue;
        }
    }
 
    while(true)
    {
        try
        {
            cout << "try to select to oracle" << endl;
            otl_nocommit_stream os(1, strMonitorSql.c_str(), db);
            os.close();
        }
        catch(otl_exception& p)
        
            cerr<<p.msg<<endl; 
            cerr<<p.stm_text<<endl; 
            cerr<<p.sqlstate<<endl; 
            cerr<<p.var_info<<endl; 
            cout<<"select fail "<<endl;
            continue;
        }
 
        sleep(3);
    }
     
    cout<<"Connected to Database success"<<endl;
    db.logoff();
     
  return 0;
}

  Makefile如下

objects = connect_oracle
SUFFIX=
 
CC = g++
 
CPPFLAGS =  -O2 -fpic -ftemplate-depth-64  -m64 -ggdb 
# CPPFLAGS =  -g 
 
#编译OCI程序时所用到的头文件路径  
INCLUDE_PATH = -I ${ORACLE_HOME}/rdbms/public -I $(OB_REL)/include/ -I $(OB_REL)/include/3rd/otl -I .
#编译OCI程序时所用到的静态链接库路径  
LIB_PATH = -L${ORACLE_HOME}/lib/      
#编译OCI程序时所用到的静态链接库    
LIBS = -lclntsh  
 
.PHONY:all
     
all:$(objects)
 
$(objects):%$(SUFFIX):%.cpp
    $(CC)  $< $(CPPFLAGS) ${INCLUDE_PATH}  ${LIBS} ${LIB_PATH} -o  $@   
 
.PHONY:clean
clean:    
    rm -f ./core* ${objects}

  对于三种情况,OTL抛出的oracle的异常,都是不同的

  第一种:ORA-12543: TNS:destination host unreachable

  第二种:ORA-12541: TNS:no listener

  第三种:ORA-03114: not connected to ORACLE

  对于这三种情况,循环连接,使用top或者pmap,都没有发现内存增长的情况,这让我对之前框架人员说的OCI的内存泄露产生了怀疑。有时候,只需一小段程序,就能检验出来某个重大的问题,就像这个问题,我选择了相信了一个同事,却忽略了如果OCI有问题,ORACLE这么大的商业公司,应该很及时的发现,怎么会任由这个问题一直存在,并且网络上没有关于任何OCI内存泄露的帖子。

  排除了OCI和OTL的问题,则可能是框架程序的问题,我使用了valgrind这个工具,对程序进行了内存泄露的测试,下一篇文章,介绍下valgrind的用法。

一个内存泄露问题的分析和处理(一),布布扣,bubuko.com

一个内存泄露问题的分析和处理(一)

标签:des   blog   class   code   ext   color   

原文地址:http://www.cnblogs.com/xiaomengaliang/p/3716676.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!