Re: Memory full

2005-01-12 Thread Octavian Rasnita
Hi,

Here is an example of a program and a perl module that parses a .xls file
and eats the whole memory.
I have tried it under Linux and Windows and it has the same problem under
both OSs, so it has big bugs.

I have tried using that destructor class in the perl module but I think what
I have done is not correct.

Thank you for telling me how to solve this issue.

The program executes a method from the module but it doesn't need any result
of that method, because it just parse a .xls file, get some results and
inserts them into MySQL, then the program does the same with the next file,
and so on.

The program:

use lib .;
use strict;
use Parse;

my $f = Parse-new;

opendir(DIR, .);
my @files = readdir DIR;
closedir DIR;

foreach my $file(@files) {
next unless $file =~ /\.xls$/i;

$f-parse($file);
}

The module:

package Parse;

use strict;
use Spreadsheet::ParseExcel;
use DBI;

my $dbh = DBI-connect(DBI:mysql:database=bvb;host=127.0.0.1, root,
undef, {RaiseError=1, PrintError=0});

sub new {
my $init = shift;
my $class = ref($init) || $init;
my $self = { @_ };
return bless($self, $class);
}

sub parse {
my $self = shift;
my $file = shift;

my $book = Spreadsheet::ParseExcel::Workbook-Parse($file);

my $sheet = ${$book-{Worksheet}}[0];

my %f;
for(my $i = 0; $i = 1000; $i++) {

my ($cod, $name);
my $market = $sheet-{Cells}[$i][3]-{Val};

if ($market =~ /total|regular|deal|odd lot/i and
$sheet-{Cells}[$i][6]-{Val} =~ /^[\d,.]+$/) {

if ($sheet-{Cells}[$i][1]-{Val} =~ /^\w{3,4}[\*\+]?$/) {
$cod = $sheet-{Cells}[$i][1]-{Val};
$cod =~ s/[\*\+]$//;
$name = $sheet-{Cells}[$i][2]-{Val};
}
elsif ($sheet-{Cells}[$i-1][1]-{Val} =~ /^\w{3,4}[\*\+]?$/) {
$cod = $sheet-{Cells}[$i-1][1]-{Val};
$cod =~ s/[\*\+]$//;
$name = $sheet-{Cells}[$i-1][2]-{Val};
}
elsif ($sheet-{Cells}[$i-2][1]-{Val} =~ /^\w{3,4}[\*\+]?$/) {
$cod = $sheet-{Cells}[$i-2][1]-{Val};
$cod =~ s/[\*\+]$//;
$name = $sheet-{Cells}[$i-2][2]-{Val};
}
elsif ($sheet-{Cells}[$i-3][1]-{Val} =~ /^\w{3,4}[\*\+]?$/) {
$cod = $sheet-{Cells}[$i-3][1]-{Val};
$cod =~ s/[\*\+]$//;
$name = $sheet-{Cells}[$i-3][2]-{Val};
}

$f{$cod}{$market}{name} = $name;
$f{$cod}{$market}{vn} = $sheet-{Cells}[$i][4]-{Val};
$f{$cod}{$market}{per} = $sheet-{Cells}[$i][5]-{Val};
$f{$cod}{$market}{close} = $sheet-{Cells}[$i][6]-{Val};
$f{$cod}{$market}{change} = $sheet-{Cells}[$i][7]-{Val};
$f{$cod}{$market}{open} = $sheet-{Cells}[$i][8]-{Val};
$f{$cod}{$market}{max} = $sheet-{Cells}[$i][9]-{Val};
$f{$cod}{$market}{min} = $sheet-{Cells}[$i][10]-{Val};
$f{$cod}{$market}{average} = $sheet-{Cells}[$i][11]-{Val};
$f{$cod}{$market}{volume} = $sheet-{Cells}[$i][12]-{Val};
$f{$cod}{$market}{value} = $sheet-{Cells}[$i][13]-{Val};
$f{$cod}{$market}{trades} = $sheet-{Cells}[$i][14]-{Val};
$f{$cod}{$market}{max52} = $sheet-{Cells}[$i][15]-{Val};
$f{$cod}{$market}{min52} = $sheet-{Cells}[$i][16]-{Val};
$f{$cod}{$market}{van} = $sheet-{Cells}[$i][17]-{Val};
}
}

my ($year, $mon, $mday) = $file =~ /trades(\d\d\d\d)(\d\d)(\d\d)\.xls$/gi;
my $date = $mon/$mday/$year;

#Create the table if it is not there
my $rapoarte_t = $dbh-do(create table if not exists temp_rapoarte(
symbol varchar(10) not null,
name varchar(255) not null,
market varchar(10) not null,
date date not null,
open varchar(20) not null,
high varchar(20),
low varchar(20),
close varchar(20) not null,
volume varchar(20) not null,
vn varchar(20),
per varchar(20),
change_ varchar(20),
average_ varchar(20),
value_ varchar(30) not null,
trades varchar(5),
min52 varchar(20),
max52 varchar(20),
van varchar(20),
primary key(symbol, date, market)
));

#Insert into database
my $rapoarte_i = $dbh-prepare(insert ignore into temp_rapoarte values(?,
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?));

foreach my $cod(sort keys %f) {
foreach my $market(keys %{$f{$cod}}) {
$rapoarte_i-execute($cod, $f{$cod}{$market}{name}, $market,
$year-$mon-$mday, $f{$cod}{$market}{open}, $f{$cod}{$market}{max},
$f{$cod}{$market}{min}, $f{$cod}{$market}{close}, $f{$cod}{$market}{volume},
$f{$cod}{$market}{vn}, $f{$cod}{$market}{per}, $f{$cod}{$market}{change},
$f{$cod}{$market}{average}, $f{$cod}{$market}{value},
$f{$cod}{$market}{trades}, $f{$cod}{$market}{min52},
$f{$cod}{$market}{max52}, $f{$cod}{$market}{van});

}
}

}

sub DESTROY {
my $self = shift;
undef $self;

#I don't know if this sub helps, or if it is correctly written
}

1;

I can send you a .xls file if you think it will help, but I guess the errors
of my program or module are obvious.

Thank you.

Teddy

- Original Message - 
From: Jay [EMAIL PROTECTED]
To: Perl Beginners List beginners@perl.org
Sent: Wednesday, January 12, 2005 12:22 AM
Subject: Re: Memory full


 On Mon, 10 Jan 2005 12:53:50 +0200, Octavian Rasnita [EMAIL PROTECTED]
wrote:
  Hi,
 
  I have made a perl module object oriented which is something like this:
 

  Then I access the parse() method in another program that feeds the
module
  with more Excel files (around 500 files).
 
  After more files parsed (around 300), the memory

Re: Memory full

2005-01-12 Thread Dave Gray
 Here is an example of a program and a perl module that parses a .xls file
 and eats the whole memory.
 I have tried it under Linux and Windows and it has the same problem under
 both OSs, so it has big bugs.
[snip]
 #Insert into database
 my $rapoarte_i = $dbh-prepare(insert ignore into temp_rapoarte values(?,
 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?));
 
 foreach my $cod(sort keys %f) {
   foreach my $market(keys %{$f{$cod}}) {
 $rapoarte_i-execute(...);
   }
 }

You should call $rapoarte_i-finish() here. I know if you're using
Oracle, not finishing will keep cursors open and that could
potentially be hogging memory like you're experiencing. Not sure about
other databases. What database are you using? Let us know if this
solves your problem.

 sub DESTROY {
 my $self = shift;
 undef $self;
 
 #I don't know if this sub helps, or if it is correctly written
 }

This is correctly written, but it's kind of redundant... because if
something is getting garbage collected, it's going to get undef'd
anyway. Unless you have circular references or some other oddity (see
Programming Perl v3, chapter 12). Which it doesn't look like is the
case, at first glance.

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Memory full

2005-01-12 Thread Jay
On Wed, 12 Jan 2005 12:24:00 +0200, Octavian Rasnita [EMAIL PROTECTED] wrote:

 The program:
 
 use lib .;
 use strict;
 use Parse;
 
 my $f = Parse-new;
 
 opendir(DIR, .);
 my @files = readdir DIR;
 closedir DIR;
 
 foreach my $file(@files) {
 next unless $file =~ /\.xls$/i;
 
 $f-parse($file);
 }


 sub DESTROY {
 my $self = shift;
 undef $self;
 
 #I don't know if this sub helps, or if it is correctly written
 }
 

Teddy,

There are a couple of things going on here.  The last one is the
destructor.  Perl should Garbage collect automatically.  The only time
you need to give it a push, is if you end up creating references to
references.  the Garabge collector does actually get trid of things,
it just lowers their refcount by one.  Now that youwe've seen you
code, this probably isn't your problem, and messing with $self is
dangerous if you don't need to do it.

You're real issue here is scoping.  Once you call new, that object
stays in scope until it passes out of scope.  You call new at the
beginning of the program, and then go into a forecah loop, and keep
adding refferences to Workbook-Parse() objects, and then garbage
collection isn't done until the end.  This is what allows you to only
open the database connection once, but it causes things to pile up in
memory.

If you don't mind incurring the extra overhead on the database server,  move

$f = Parse-new ;

Inside the foreach loop.  This will ensure that that the Parse object
is destroyed at the end of each iteration:

foreach my $file(@files) {
 next unless $file =~ /\.xls$/i;
 $f = Parse-new ; 
 $f-parse($file);
}

If you want to keep the database connection open,  you need to make
sure that the reference counts of $f and $book fall to zero each time
sub Parse exits.  Because they're references, they don't go out of
scope when the subroutine exits, so they and the  Workbook-Parse
objects keep piling up.  when you're debugging, you can use
Devel::Peek to keep track of the references and make sure the counts
go down.  Also take a look at Chapter 11 and particularly recipe 11.5
in the _Perl Cookbook_.

HTH,

--jay

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Memory full

2005-01-11 Thread Jay
On Mon, 10 Jan 2005 12:53:50 +0200, Octavian Rasnita [EMAIL PROTECTED] wrote:
 Hi,
 
 I have made a perl module object oriented which is something like this:
 

 Then I access the parse() method in another program that feeds the module
 with more Excel files (around 500 files).
 
 After more files parsed (around 300), the memory is full.
 
 Please tell me what can I do to free the memory after each file parsed by
 the module.
 
 I run this program manually or by a cron job, but I would like to know
 better how to free the memory because I might want to use it under mod_perl.
 
 Thank you very much for any tip.
 
 Teddy
 

Teddy,

This is one of the tricky parts of objects and pass-by-reference
applications: a refence never goes out of scope, so it's memory is
never reclaimed.  Think about what would happen, for example, if you
created 500 hundred references to DBD::mysql handles, or similar, and
never called $handle-disconnect() on any of them.

What you need to do is write a method that, when called, will make
sure that all that everything associated with the object it's passed
is dereferenced.  In the main program, you can call it explicitly when
you're done with each object when you're done with it.

When you call it, the code should look something like this:

foreach (@files) {
 my $obj = yourmod-parse($_) ;

 # do something to $obj 

 $obj-destroy() or warn can't dereference ;
}

HTH

--jay

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Memory full

2005-01-10 Thread Octavian Rasnita
Hi,

I have made a perl module object oriented which is something like this:

use Spreadsheet::ParseExcel;
use DBI;

...

sub new {
...
}

sub parse {

my $dbh = ...;

#here some Excel files parses and database updates...
}

Then I access the parse() method in another program that feeds the module
with more Excel files (around 500 files).

After more files parsed (around 300), the memory is full.

Please tell me what can I do to free the memory after each file parsed by
the module.

I run this program manually or by a cron job, but I would like to know
better how to free the memory because I might want to use it under mod_perl.

Thank you very much for any tip.

Teddy


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Memory full

2005-01-10 Thread Jenda Krynicky
From: zentara [EMAIL PROTECTED]
 On Mon, 10 Jan 2005 12:53:50 +0200, [EMAIL PROTECTED] (Octavian Rasnita)
 wrote:
 
 Hi,
 
 I have made a perl module object oriented which is something like
 this:
 
 use Spreadsheet::ParseExcel;
 use DBI;
 
 Then I access the parse() method in another program that feeds the
 module with more Excel files (around 500 files).
 
 After more files parsed (around 300), the memory is full.
 
 Please tell me what can I do to free the memory after each file
 parsed by the module.
 
 I run this program manually or by a cron job, but I would like to
 know better how to free the memory because I might want to use it
 under mod_perl.
 
 Thank you very much for any tip.
 
 Maybe you can get something out of
 
 http://perlmonks.org/index.pl?replies=1;displaytype=print;node_id=3797
 43
 
 Reducing the memory usage of Spreadsheet::ParseExcel

Good to know, but this'd require rather big changes in the script. 
Besides it doesn't seem the problem is in parsing a single file. It 
seems there is a memory leak either in the script or in the module 
that causes the memory not to be freed when done with a file.

Octavian, could you try to create a minimal example that displays 
this behaviour? Or, if not too long, show us the actual code?

Jenda
= [EMAIL PROTECTED] === http://Jenda.Krynicky.cz =
When it comes to wine, women and song, wizards are allowed 
to get drunk and croon as much as they like.
-- Terry Pratchett in Sourcery


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response