Link to home
Start Free TrialLog in
Avatar of circler
circlerFlag for Lebanon

asked on

Delphi "Out Of Memory" Error

Hey there,

I needed a code to act like a bruteforcer so I found one, but the problem is I don't want to use TStringList, so I replaced it with array of strings and added some modifications.
The problem is when I run the code, after a certain time I get "Out Of Memory" error.

I hope someone can show me where is my error, I use FreeMem and SetLength to free the array of string each iteration.
Code is below..

Regards
function   bruteforce(astring:   string  ;substr:   string  ;  startlen: integer;
endlen: integer): LongInt; 
var   i,n,x: integer;
bi,bc,br:integer;
npw:   string  ;
counter:integer;
bhlplst: array of string;
bcluster : array of string;
bresults : array of string;
label   step1;
begin
bi := 0;
bc := 0;
br := 0;
//hlplst := TStringList.Create;    //The left column
//cluster := TStringList.Create;   //The middle section
//results := TstringList.Create;   //The combinations created
for   x := 1   to   length(substr)   do begin
//hlplst.Add(substr[x]);
SetLength(bhlplst, bi + 1);
bhlplst[bi] := substr[x];
Inc(bi);
end  ;
 
step1:
for   i := 0   to   {hlplst.Count}bi - 1   do begin
for   n := 1   to   length(astring)   do begin
//npw := hlplst.strings[i]+astring[n];
npw := bhlplst[i] +  astring[n];
//cluster.Add(npw);
 
SetLength(bcluster, bc + 1);
 
bcluster[bc] := npw;
 
Inc(bc);
 
 
if   length(npw) >= startlen   then
begin
//results.Add(npw);
//SetLength(bresults,br + 1);
//bresults[br] := npw;
//Inc(br);
Form1.Memo1.Lines.Add(npw);
end;
end  ;
end  ;
//hlplst.clear;
bi := 0;
SetLength(bhlplst, bi);
FreeMem(bhlplst);
//hlplst.addstrings(cluster);
SetLength(bhlplst, bc );
for counter := 0 to bc - 1 do
begin
bhlplst[bi] := bcluster[counter];
Inc(bi);
end;
//cluster.Clear;
bc := 0;
SetLength(bcluster, bc);
FreeMem(bcluster);
if   length(npw) + 1 <= endlen   then     goto   step1;
//hlplst.Clear;
bi := 0;
SetLength(bhlplst,bi);
FreeMem(bhlplst);
result := 0;
end  ;

Open in new window

Avatar of circler
circler
Flag of Lebanon image

ASKER

bump
Avatar of circler

ASKER

I'm still waiting someone to help me out.. thanks
the reason you are running out of memory is that the TStrings property of the Form1 Memo1 memobox keeps growing infinitely long:

this is the culprit:

        Form1.Memo1.Lines.Add(npw);


At some point, you need to do a "Form1.Memo1.Clear;"   However, keep in mind that this doesn't actually RELEASE the memory there. A TStringList always just grows until you "Free" them.  But if you do a 'clear' then at least the Lines[0] get reused, and the Lines[1], etc.

and, a little nicer formatting would be, well, nice.  Like below. Makes readability much easier.

Also, you don't really need to do a Freemem after a SetLength(x,0)  In fact, the array of strings are local anyway, so they go away anyway.  

But the Form's memobox does not go away, and it will grow indefinitely the way you coded it.  Somewhere, once you are done with those strings, you should free the memobox. Maybe do the Memobox in code (instead of just dropping it on the form) so you can create it and free it explicitly.


function bruteforce(astring,substr: string; startlen, endlen: integer): LongInt;
var  
  counter,i,n,x,bi,bc,br:integer;
  npw: string;
  bhlplst,bcluster,bresults: array of string;
label  
  step1;
begin
  bc := 0;    br := 0;
  bi := length(substr);    // why reset this on every loop; you already know it's max size
  SetLength(bhlplst, bi + 1);
  for x := 1 to length(substr)   do
    bhlplst[x-1] := substr[x];

  step1:
  for   i := 0 to bi - 1   do
    for   n := 1   to   length(astring)   do
      begin
      npw := bhlplst[i] +  astring[n];
      SetLength(bcluster, bc + 1);
      bcluster[bc] := npw;
      inc(bc);
      if length(npw) >= startlen   then
        Form1.Memo1.Lines.Add(npw);
      end;

  bi := 0;
  SetLength(bhlplst,bi);
  FreeMem(bhlplst);
  SetLength(bhlplst,bc);
  for counter := 0 to bc - 1 do
    begin
    bhlplst[bi] := bcluster[counter];
    inc(bi);
    end;
  bc := 0;
  SetLength(bcluster, bc);
  FreeMem(bcluster);
  if length(npw) + 1 <= endlen   then    
    goto   step1;
  bi := 0;
  SetLength(bhlplst,bi);
  FreeMem(bhlplst);
  result := 0;
end;
Avatar of circler

ASKER

JosephGlosz, thanks for your help, but I tried your code and I'm still getting Out Of Memory error ;(
you can try it yourself and see..
I commented this part too "//Form1.Memo1.Lines.Add(npw);" and still getting same problem
I hope you can find out what's going on
Thanks!
running the function below, with the call

 i := bruteforce('12345','23',1,5);

I can see what is happening. The"endlen" is the length of the strings in which you will try ALL permutations.  So that is 5, then you will generate 99,999 strings, in addition to the 9,999 strings you generated in the previous pass, and the 999 strings before that.

When I run the above call (see below) it runs and completes just fine.

But if that endlen number is much larger, say 7, then you are creating 10 million strings.   At some point, there is no wonder you run out of memory.

What parameters do you call BruteForce with?  I'll try the same thing and see if we can't optimize this.




function bruteforce(astring,substr: string; startlen, endlen: integer): LongInt;
var
  counter,i,n,x,bi,bc,br:integer;
  npw: string;
  bhlplst,bcluster,bresults: array of string;
label
  step1;
begin
  bc := 0;    br := 0;
  bi := length(substr);    // why reset this on every loop; you already know it's max size
  SetLength(bhlplst, bi + 1);
  for x := 1 to length(substr)   do
    bhlplst[x-1] := substr[x];

  step1:
  for   i := 0 to bi - 1   do
    for   n := 1   to   length(astring)   do
      begin
      npw := bhlplst[i] +  astring[n];
      SetLength(bcluster, bc + 1);
      bcluster[bc] := npw;
      inc(bc);
      if length(npw) >= startlen   then
        Form1.Memo1.Lines.Add(npw);
      end;

  bi := 0;
  SetLength(bhlplst,bc);
  for counter := 0 to bc - 1 do
    begin
    bhlplst[bi] := bcluster[counter];
    inc(bi);
    end;
  bc := 0;
  SetLength(bcluster, bc);
  if length(npw) + 1 <= endlen   then
    goto step1;
  bi := 0;
  SetLength(bhlplst,bi);
  result := 0;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  i: longint;
begin
  i := bruteforce('12345','23',1,5);
end;
Avatar of circler

ASKER

What I am trying is:
 bruteforce('ABCDEFGHIJKLMNOPQRSTUVWXYZ','ABCDEFGHIJKLMNOPQRSTUVWXYZ',4,4);

Thanks in advance :)
ok, I'll try it at work in the morning.  
Avatar of circler

ASKER

Thank you, I'm waiting :)
Avatar of circler

ASKER

Does anyone have an idea?
Avatar of circler

ASKER

Can I please get someone's attention ;x, it's been a week.
I'll try tomorrow morning if I can. I've been away for a while due a family emergency, which is still ongoing.
Well, running it through the debugger, I can see what is happening now.  I think you just have some phenomenally inefficient code.  If you want to use the algorithm as is, you'll probably need to store the bcluster[x] values in a database instead of in memory.

Here is what happens. Your initial double for loop goes from 0 to 25 and 1 to 26. So eventually, you set the bcluster array to a length of 26*26 or 676.   At a bc of 30, bcluster is
('AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD')

The 2nd time through the loops, bi starts at 676 so bc ends up at 17576, because the for loops say:

for i := 0 to 675 do for n := 1 to 26 do....  

that's because in this loop below, bi is incremented to the value of bc, which is always i and n multiplied together. On the first time through, that is 26*26; the second time, it's 26*676, etc etc.

  for counter := 0 to bc - 1 do
    begin
    bhlplst[bi] := bcluster[counter];
    inc(bi);
    end;

So, eventually you will try to allocate 26! (26 factorial) bytes of memory (and possibly that, squared).  No wonder you run out of memory.

Basically you are trying hold all possible permutations of the alphabet, A..Z, in memory, starting with 'AA' and ending with 'ZZZZZZZZZZZZZZZZZZZZZZZZZZ'.

My calculator lists 26! = 403,291,461,126,605,635,584,000,000.  That's :

403,291,461,126,605,635,584,000 Kilobytes or
403,291,461,126,605,635,584 megabytes or
403,291,461,126,605,635 GB or
403,291,461,126,605 Terabytes

So unless I am miscalculating, you are looking to store 400 trillion terabytes in memory...

I don't think this is possible. You might want look into databases. ;-)

Avatar of circler

ASKER

Thank you very much JosephGlosz for your explanantion.. :)
But what I need from this code is generate test of the combinations which will start with AAAA and end with ZZZZ each time, so if there is a solution to have the same concept without storing in a variable, and testing the combination each iteration, I'd be very thankful..
ASKER CERTIFIED SOLUTION
Avatar of JosephGlosz
JosephGlosz
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of circler

ASKER

I would've liked to have a full solution, but it's thanks JosephGlosz for trying to help, got 70% of solution
Regards