免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3564 | 回复: 3

循环使用DBD::Oracle时,内存使用量不断上涨,如何控制? [复制链接]

论坛徽章:
0
发表于 2011-08-23 21:22 |显示全部楼层
本帖最后由 jjqing 于 2011-08-23 23:59 编辑

今天在windowsXP客户端上面使用dbd::oracle对数据库进行大批量查询时发现,perl.exe对内存的使用是不断上涨,直到2G时,报out of memory然后退出。

为了测试这个问题,我用了一个简单的查询来进行模拟,使用了三种方法来使用DBD::Oracle,由于简单查询不可能把内存使用达到2G,因此,我只是想说明,在这三种方法中,perl.exe的内存都是在不断上涨的,想请各位指导一下,如何释放内存,如何控制对内存的使用,谢谢!

测试方法:
一、使用标准的DBD::Oracle用法,即只connect()一次,然后对每个语句做prepare,再execute,再fetch,再finish,最后在程序退出的时候执行disconnect():

  1. use strict;
  2. use warnings;
  3. use diagnostics;
  4. use Smart::Comments '###';

  5. use DBI;
  6. use DBD::Oracle qw(:ora_session_modes);

  7. my $user = "system";
  8. my $passwd = "oracle";
  9. my $tns = "ORCL_DEV";
  10. my $dsn = "dbi:Oracle:$tns";
  11. my $dbh = DBI->connect( $dsn, $user, $passwd, {RaiseError => 0} );

  12. for ( my $i = 1; $i < 2000 ; $i++ ) {
  13.     login_once($i);
  14. }

  15. sub login_once {
  16.     my $i = shift;
  17.     print "do sql test $i\n";
  18.     my $sql = "SELECT count(*) total_user FROM dba_users";
  19.     my $sth = $dbh->prepare( $sql );
  20.     $sth->execute( );
  21.     my @rows = $sth->fetchrow_array;
  22.     print "\t total user is $rows[0] \n";

  23.     $sth->finish();
  24. }

  25. sleep 60000;
  26. $dbh->disconnect();

复制代码
二、对方法一做一处修改,在循环过程中不执行finish()操作:

  1. use strict;
  2. use warnings;
  3. use diagnostics;
  4. use Smart::Comments '###';

  5. use DBI;
  6. use DBD::Oracle qw(:ora_session_modes);

  7. my $user = "system";
  8. my $passwd = "oracle";
  9. my $tns = "ORCL_DEV";
  10. my $dsn = "dbi:Oracle:$tns";
  11. my $dbh = DBI->connect( $dsn, $user, $passwd, {RaiseError => 0} );

  12. for ( my $i = 1; $i < 2000 ; $i++ ) {
  13.     login_once($i);
  14. }

  15. sub login_once {
  16.     my $i = shift;
  17.     print "do sql test $i\n";
  18.     my $sql = "SELECT count(*) total_user FROM dba_users";
  19.     my $sth = $dbh->prepare( $sql );
  20.     $sth->execute( );
  21.     my @rows = $sth->fetchrow_array;
  22.     print "\t total user is $rows[0] \n";
  23.     #$sth->finish();
  24. }

  25. sleep 60000;
  26. $dbh->disconnect();

复制代码
三、每执行一个sql,进行一次connect(),然后依次是prepare/execute/fetch/finish/disconnect():

  1. use strict;
  2. use warnings;
  3. use diagnostics;
  4. use Smart::Comments '###';

  5. use DBI;
  6. use DBD::Oracle qw(:ora_session_modes);

  7. my $user = "system";
  8. my $passwd = "oracle";
  9. my $tns = "ORCL_DEV";
  10. my $dsn = "dbi:Oracle:$tns";

  11. for ( my $i = 1; $i < 2000 ; $i++ ) {
  12.     login_everyonce($i);
  13. }

  14. sleep 60000;

  15. sub login_everyonce {
  16.     my $i = shift;
  17.     print "do sql test $i\n";
  18.     my $dbh = DBI->connect( $dsn, $user, $passwd, {RaiseError => 0} );
  19.     my $sql = "SELECT count(*) total_user FROM dba_users";
  20.     my $sth = $dbh->prepare( $sql );
  21.     $sth->execute( );
  22.     my @rows = $sth->fetchrow_array;
  23.     print "\t total user is $rows[0] \n";
  24.     $sth->finish();
  25.     $dbh->disconnect();
  26. }


复制代码
通过以上三种方法,我进行了2000次循环,测试结果如下:
    脚本名称    进程ID  使用内存    CPU时间
    dbd1.pl     5568      17,840 K  00:00:02
    dbd2.pl     6404      17,840 K  00:00:02
    dbd3.pl     4192      18,716 k  00:00:45

snap.jpg
测试结果让我感到奇怪:
方法一和方法二,对windows客户端来说,使用的内存数量完全一样,没有差别。
对于方法三,我原以为它是最省内存的,结果它使用的内存是最多的。

原因不明!但是看起来,内存上涨,好像不是DBD::Oracle的错!那是哪里错了呢?

请各位帮忙分析一下,为什么一条小小的select count(*) from dba_usrs,执行了2000次之后,会占用17M的内存呢?是哪个变量占用了这些内存?
并且它对内存的使用,是随着每个循环,而不断加大的,从来没有释放过。

请问,有办法释放或控制内存么?因为这个测试里面只是很小的查询,如果是很大的查询,几十个循环下来,perl.exe进程立即超过2G内存了。。。

谢谢各位!如果我还有描述得不清楚的地方,请各位多多指正,我会立即补充!

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2011-08-24 08:20 |显示全部楼层
回复 1# jjqing

先说代码本身
strict warnings diagnostics倒是都用了,可DBI是有很多错误检查机制的,connect,prepare,execute,fetch等都有。一定要检查函数返回值。

另外,为什么prepare,execute,fetch而不是selectrow_arrayref?为的是prepare一次,多次execute。你prepare2000次,就失去了所有的意义,还不如直接用selectrow_arrayref。

还有那个平台,我是极其不看好win下的Perl,不知道你Oracle是不是远程的,很多问题会发生在win下。

最后,建议把diagnostics关了吧,除非程序有错误,并且你看不懂错误输出。程序没错误还是关了它。

论坛徽章:
0
发表于 2011-08-24 15:58 |显示全部楼层
回复 2# py


    谢谢!

我等下到Linux下面测试一把看看,结果是否跟windows一样。

论坛徽章:
0
发表于 2011-08-25 09:43 |显示全部楼层
回复 2# py


    果然是啊!

    我把第1个脚本改成循环200000万次,在Linux下运行,可以看到占用的物理内存和虚拟内存稳定保持在17M和71M两个数字,,并且系统的used memory也稳定保持在300M这个数字,不像在windows下面,随着每个循环而不断扩大。

    看来我又要重新回到Linux平台了!

    谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP