4

I am not new to perl , but I couldn't able to solve this usecase.

Here is my problem statement:

I am using Activestate perl 5.12 32-bit. I want to hold some 32 x 8MB array of double in Memory at a time. unfortunately, I am getting 'out of memory' error in this case. for example, the code below will lead to out of memory.

my $aref1 = [(.25) x (8*1024*1024)];
my $aref2 = [(.25) x (8*1024*1024)];
my $aref3 = [(.25) x (8*1024*1024)];
my $aref4 = [(.25) x (8*1024*1024)];
my $aref5 = [(.25) x (8*1024*1024)];
my $aref6 = [(.25) x (8*1024*1024)];
my $aref7 = [(.25) x (8*1024*1024)];
my $aref8 = [(.25) x (8*1024*1024)];
my $aref9 = [(.25) x (8*1024*1024)];
my $aref10 = [(.25) x (8*1024*1024)];

Is there any way to efficiently handle it?

Note: In any case, the access to the arrays is needed at any time of execution as fast as possible (since the user cannot wait soo long)

the options I have tried:

  1. DBM::Deep - It takes more time
  2. PDL - Gives 'out of memory' error for 32 x 8MB array of double

Awaiting your valuable suggestions!

3 Answers 3

11

32 arrays * 8 Mi-doubles/array * 8 bytes/double = 2 GiB.

32-bit processes on Windows only have 2GiB of usable address space. Your raw data would take up all available address space, leaving nothing for the data structure's overhead, perl, your program and other variables. The only way it's going to fit in memory is if you switch to a 64-bit Perl. Otherwise, you will have to contend with a necessarily slower solution.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes. I could understand the problem now. So I am looking for any other intermediate solution (like Inline::C, Inline. Is it possible to store the data globally in Inline::C ?
No, the raw data takes more memory that you have. Switching language is not going to help. You need to switch to a 64-bit process or figure out a way of not having all the data in memory at once.
3

This will create a perl value for each element, which will be quite heavy. You might want to look at something that stores the values as doubles, such as Tie::CArray or Tie::Array::PackedC.

1 Comment

Also, you might not want to create millions of temporary values in the process. Initializing in a loop might be much more feasible.
2

Here is what I get on my Windows XP SP3 system using ActiveState Perl 5.14.2. Task manager was showing Commit charge: 778M/3958M when I ran the following script:

#!/usr/bin/env perl

use strict;
use warnings;

use Devel::Size qw(total_size);

my $unit = 1024 * 1024;
my $topj = (8 * $unit) - 1;
my @data;

for my $i (0 .. 31) {
    print "$i: ";
    my @row;
    $#row = $topj;
    for my $j (0 .. $topj) {
        $row[$j] = 0.25;
    }
    push @data, \@row;
    printf "%.0f\n", total_size(\@data)/$unit;
}

Output:

C:\temp> yy
0: 224
1: 448
2: 672
3: 896
4: 1120
5: 1344
6: 1568
7: 1792
Out of memory!
8:

On the other hand, the following C program does better:

#include <stdlib.h>
#include <stdio.h>

#define ROWSIZE 8*1024*1024

int main(void) {
    int n = 1;
    while (calloc(ROWSIZE, sizeof(double))) {
        printf("%d: success!\n", n);
        n += 1;
    }
    return 0;
}

Output:

1: success!
2: success!
3: success!
…
26: success!
27: success!

for the same 1.7GB footprint.

1 Comment

I am looking for any other intermediate solution (like Inline::C, Inline ). Is it possible to store the data globally in Inline::C ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.