Allowed memory size of {certain size} bytes exhausted (tried to allocate {certain size} bytes)

I have tried to optimize my code to use less memory, can’t seem to get it to work.

My current code works up until $t=21;
I need it to be able to go till $t = 65;

<?php 
    $t = 6;
    $bit1 = "0,1";
    $tempArr = explode(',', $bit1);

    for($i = 1; $i < $t; $i++){

        if($i > 65)
            break;

        $normArr = $tempArr;

        $revArr = array();
        $size = sizeof($normArr);
        for($j=$size-1; $j>=0; $j--){
              $revArr[] = $normArr[$j];
        }

        
        $cnt = count($normArr);
        for($k=0; $k<$cnt; $k++){
            $normArr[$k] = str_pad($normArr[$k], $i+1, "0", STR_PAD_LEFT);
        }

        $cn = count($revArr);
        for($l=0; $l<$cn; $l++){
            $revArr[$l] = str_pad($revArr[$l], $i+1, "1", STR_PAD_LEFT);
        }

        $tempArr = $normArr;

        $c=count($revArr);
          for($j=0; $j<$c; $j++) 
              {
                 $tempArr[]=$revArr[$j];  // each element  1 by 1 store inside the array $a[]
              }
    }
    

    $sliced = array_slice($tempArr, -$t);

    $count = 1;

    foreach($sliced as $slice){
        if($count > $t)
            break;
        echo $slice."\n";
        $count++;
    }

 ?>

Increasing the memory size is not an option for me in this case.

When i try that code locally, using:

echo '<p>'.memory_get_peak_usage(false).'</p>';

at the end to get the peak memory usage, PHP says that it used a maximum of 408416 bytes, no out of memory errors. What are you trying to do with the script (the purpose of the script)?

Thanks for having a look…

Please change the value of $t to something greater than 20… I find that memory exhausts when I give it something from 21 upwards.

The script is supposed to print a list of binary digits increasing by one bit following a particular order.

Take “0 1”

  • reverse it to become “1 0”
  • add zeroes to the front of the normal order to get “00 01”
  • add ones to the front of the reversed order to get “11 10”
  • merge both which would give “00 01 11 10”
  • repeat pattern for $t amount of times

so $t = 2 would end as “00 01 11 10”
$t = 3 would end as “000 001 011 010 110 111 101 100”

I eventually have to print a only a part of the final outcome… but I currently cannot get it to iterate more than 20 times.

If there’s a lighter/more efficient way to achieve this, I’m willing to do that.

130784

This is what I get from echo '<p>'.memory_get_peak_usage(false).'</p>'; on my end, but that also only works for $t=values less than 21;

91409080

when $t=19

I guess you could put some of that into functions so that transient values would nor be retained in memory. Or you could try using unset() for large values once you’re done with them.

But I have to wonder why you’re not using decbin() ?
http://php.net/manual/en/function.decbin.php

Try using:

  1. strings all the time
  2. Prefix first and second string with 0 and 1 respectively
  3. Str_replace space with space 0 and space 1 respectively
  4. Debug, Temporary echo the two strings
  5. Final iteration concatenate two strings
  6. Splice concatenated strings

Unable to test on my tablet.

Edit:
I forgot to mention PHP strrev () function

http://php.net/manual/en/function.strrev.php

I did try to use decbin early on, But it doesn’t give the same order as required. That’s why i’m looking for other alternatives.

I have tried to move some parts of the codes into functions, but it still runs out of memory inside the functions, and unset doesn’t seem to change much either.

You probably didn’t left pad the numbers so that the sort comparison would work as expected.
This does type juggling between int ↔ string that you may need to be careful about, but uses ~ 2Mb memory

<?php
/* development debugging */
error_reporting(E_ALL);
ini_set('display_errors', "TRUE");

$bin_arr = [];
$int_arr = range(0, 200);
foreach($int_arr as $int_val) {
  $bin_arr[] = str_pad(decbin($int_val), 10, 0, STR_PAD_LEFT);
}
sort($bin_arr, SORT_NUMERIC);
foreach($bin_arr as $bin_val) {
  echo $bin_val . '<br>';
}
echo number_format(((memory_get_peak_usage(TRUE)/1024)/1024)) . ' Mb';
?>

Thanks a lot for your patience.

This is quite fast and doesn’t exhaust memory but I still can get it to produce the required order.

The normal order which this gives is:
000
001
010
011
100
101
110
111

But the order i’m trying to achieve is like:
000
001
011
010
110
111
101
100

Sorry, but I’m not seeing any order in that. Can you explain it in words instead of a “like this” list?

sorry,

In the order i’m trying to achieve “11” comes before “10” this is what I tried to explain here.

please let me know if I can be a bit clearer.

Try this:

<?php 
  declare(strict_types=1);
  error_reporting(-1);
  ini_set('display_errors', '1');

  echo '<hr>';
    echo '$t = 1 would start at <b> &nbsp; 0 1 ==> 1 0 </b><br>';
    echo '$t = 2 would end as <b> 00 01 ==> 11 10 </b><br>';
    echo '$t = 3 would end as <b> 000 001 ==> 110 111 </b><br>';
    echo '$t = 4 would end as <b> 0000 0001 ==> 1110 1111 </b>';
  echo '<hr>';

  $bit1 = "0,1";
  fnSplit( $bit1 );

//===================================
function fnSplit($bit1)
{  
  $bit2 = strrev($bit1);

  $bit1 = str_replace(',', ' ', $bit1);
  $bit2 = str_replace(',', ' ', $bit2);
  $bit3 = $bit1 .' ==> ' .$bit2;

  for($iStep=0; $iStep<99; $iStep++)
  {
    $tmp = <<< ____TMP
      <dl>
        <dt> \$iStep ==> $iStep </dt>  
        <dd> \$bit1  ==> $bit1</dd>
        <dd> \$bit2  ==> $bit2 </dd>
        <dd> \$bit3  ==> $bit3 </dd>
      </dl>
____TMP;

    if( ($iStep >= 0 && $iStep<3) || ($iStep >= 97 && $iStep<=99) )
    {
      echo $tmp;
    }  
    if($iStep ===42) {echo '<hr>SKIPPING $iSteps from 4...96 <hr>';}

    $bit1 = ' ' .trim($bit1);
    $bit2 = ' ' .trim($bit2);
    $bit1 = str_replace(' ',' 0', $bit1) .'';
    $bit2 = str_replace(' ',' 1', $bit2);
    $bit3 = $bit1 .' ==> ' .$bit2;
  }// endfor; $iStep  
}

**Output:** ``` $t = 1 would start at 0 1 ==> 1 0 $t = 2 would end as 00 01 ==> 11 10 $t = 3 would end as 000 001 ==> 110 111 $t = 4 would end as 0000 0001 ==> 1110 1111

$iStep ==> 0
$bit1 ==> 0 1
$bit2 ==> 1 0
$bit3 ==> 0 1 ==> 1 0

$iStep ==> 1
$bit1 ==> 00 01
$bit2 ==> 11 10
$bit3 ==> 00 01 ==> 11 10

$iStep ==> 2
$bit1 ==> 000 001
$bit2 ==> 111 110
$bit3 ==> 000 001 ==> 111 110

Skipping $iSteps from 4…96

$iStep ==> 97
$bit1 ==> 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
$bit2 ==> 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
$bit3 ==> 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ==> 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110

$iStep ==> 98
$bit1 ==> 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
$bit2 ==> 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
$bit3 ==> 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ==> 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110

Thanks for your input, I have tried to follow your input and it brought me real close… Just a few issues. strrev doesn’t reverse the string as i’d want. It turns for example “a good boy” into “yob doog a”. but for my code to work i need it to return “boy good a” for example. so i had to fall back on array.

<?php 
header('Content-type: text/plain');
    $t = 66;
    $str0 = "0 1";
    

    for($i = 1; $i < $t; $i++){

    	//$str1 = strrev($str0);
    	$str1 = join(' ',array_reverse(explode(' ',$str0)));

        if($i > 65)
            break;

        $str0 = "0".$str0;
        $str1 = "1".$str1;

        $str0 = str_replace(" ", " 0", $str0);
        $str1 = str_replace(" ", " 1", $str1);

        $str0 = $str0." ".$str1;

        //echo "$str0\n";
    }

    echo "$str0";
 ?>

if i try to echo just the final value of $str0 outside the loop (which is what I need)… it runs out of memory.

is there another way to reverse the strings by space that’s not as thorough as strrev().

Thanks for taking the time to write this up…
the issue with this one is that it only uses the first level of 0 1 => 1 0

if you notice, the result for $t =3 in your code is different from above.

to get the result for 3 we have to

  • take 2’s result which is “00 01 11 10”
  • reverse it to get " 10 11 01 00"
  • pad the original with zeroes to get “000 001 011 010”
  • pad the reversed with ones to get “110 111 101 100”
  • merge both to get “000 001 011 010 110 111 101 100” which is the final value when $t = 3;

and for $t =4 we use the final value of $t =3 that we got using the final value of $t=2… on and on like that.

I’m sorry i’m not much of an expert, so I don’t know if i’ve explained this properly.

The last code I posted before this comment, does what I need, but runs out of memory at the point where I was forced to use an array.

Try this:

<?php 
  declare(strict_types=1);
  ini_set('display_errors', '1');
  error_reporting(-1);

# header('Content-type: text/plain');

  $t    = 32;
  $str0 = "0 1";
    
  for($j=10; $j<$t; $j++) {
    if( true ) 
    {  
      $strLen = strlen($str0);

      echo '<dl>';
      echo '<dt>$j = ' .$j .'</dt>';
        echo '<dd>strlen($str0) ==> ' . number_format( (float) $strLen ) .' Bytes</dd>';

       // MAYBE DISPLAY $str0 
       if( strlen($str0) < 2000 ) {
        echo '<dd>$str0 ==> ' .$str0 .'</dd>';
       }else{
         echo '<b> $str0 ==> FAR TOO BIG TO DISPLAY </b>'; 
       }

      echo '</dl>';  
    }  

    try {
      $str0 = fnSplit( $str0 );
    } Catch (Exception $e) {
      echo '<br><br>FAILED: $j ==> ' .$j;
      echo '<br>' .$e.getMessage();
      echo '<br>';
      exit;
    }  
  }

//================================================
function fnsplit( $str0 )  
{
  $str1 = join(' ', array_reverse(explode(' ', $str0) ) );

  $str0 = "0" .$str0;
  $str1 = "1" .$str1;

  $str0 = str_replace(" ", " 0", $str0);
  $str1 = str_replace(" ", " 1", $str1);

  $str0 = $str0." ".$str1;

  return $str0;      
}//

Output:

$j = 20
    strlen($str0) ==> 3 Bytes
    $str0 ==> 0 1

$j = 21
    strlen($str0) ==> 11 Bytes
    $str0 ==> 00 01 11 10

$j = 22
    strlen($str0) ==> 31 Bytes
    $str0 ==> 000 001 011 010 110 111 101 100

$j = 23
    strlen($str0) ==> 79 Bytes
    $str0 ==> 0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 1010 1011 1001 1000

$j = 24
    strlen($str0) ==> 191 Bytes
    $str0 ==> 00000 00001 00011 00010 00110 00111 00101 00100 01100 01101 01111 01110 01010 01011 01001 01000 11000 11001 11011 11010 11110 11111 11101 11100 10100 10101 10111 10110 10010 10011 10001 10000

$j = 25
    strlen($str0) ==> 447 Bytes
    $str0 ==> 000000 000001 000011 000010 000110 000111 000101 000100 001100 001101 001111 001110 001010 001011 001001 001000 011000 011001 011011 011010 011110 011111 011101 011100 010100 010101 010111 010110 010010 010011 010001 010000 110000 110001 110011 110010 110110 110111 110101 110100 111100 111101 111111 111110 111010 111011 111001 111000 101000 101001 101011 101010 101110 101111 101101 101100 100100 100101 100111 100110 100010 100011 100001 100000

$j = 26
    strlen($str0) ==> 1,023 Bytes
    $str0 ==> 0000000 0000001 0000011 0000010 0000110 0000111 0000101 0000100 0001100 0001101 0001111 0001110 0001010 0001011 0001001 0001000 0011000 0011001 0011011 0011010 0011110 0011111 0011101 0011100 0010100 0010101 0010111 0010110 0010010 0010011 0010001 0010000 0110000 0110001 0110011 0110010 0110110 0110111 0110101 0110100 0111100 0111101 0111111 0111110 0111010 0111011 0111001 0111000 0101000 0101001 0101011 0101010 0101110 0101111 0101101 0101100 0100100 0100101 0100111 0100110 0100010 0100011 0100001 0100000 1100000 1100001 1100011 1100010 1100110 1100111 1100101 1100100 1101100 1101101 1101111 1101110 1101010 1101011 1101001 1101000 1111000 1111001 1111011 1111010 1111110 1111111 1111101 1111100 1110100 1110101 1110111 1110110 1110010 1110011 1110001 1110000 1010000 1010001 1010011 1010010 1010110 1010111 1010101 1010100 1011100 1011101 1011111 1011110 1011010 1011011 1011001 1011000 1001000 1001001 1001011 1001010 1001110 1001111 1001101 1001100 1000100 1000101 1000111 1000110 1000010 1000011 1000001 1000000

$j = 27
    strlen($str0) ==> 2,303 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 28
    strlen($str0) ==> 5,119 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 29
    strlen($str0) ==> 11,263 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 30
    strlen($str0) ==> 24,575 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 31
    strlen($str0) ==> 53,247 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 32
    strlen($str0) ==> 114,687 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 33
    strlen($str0) ==> 245,759 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 34
    strlen($str0) ==> 524,287 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 35
    strlen($str0) ==> 1,114,111 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 36
    strlen($str0) ==> 2,359,295 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 37
    strlen($str0) ==> 4,980,735 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 38
    strlen($str0) ==> 10,485,759 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(

$j = 39
    strlen($str0) ==> 22,020,095 Bytes
$str0 ==> GETTING FAR TOO BIG TO DISPLAY :(


Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 33554440 bytes) in /home/john/www/A-KILL/a-003/kill-008.php on line 43

I get the general impression that this topic relates to a college project and the solution to use arrays or strings was incorrect.

I also think that the solution may involve working only with binary numbers where it would be far easier to manipulate the values.

If it is a college project then please post the full question.

It is not a college project.
It’s something I have been tasked with tackling at work and generally It it not compulsory to use arrays or strings… I just do not know another way to arrive at the required solution… and the one that works for me exhausts memory before $t = 65.

Maybe try working with binary numbers $bit1 = 0b01 // numeric 1

$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
                .  ' %3$s (%4$2d = %4$04b)' . "\n<br>";

echo sprintf( $format, $bit1 );  

There are many examples of using binary on the PHP Manual:

http://php.net/manual/en/language.operators.bitwise.php

Edit:
Changed Hex value 0x01 to binary 0b01

Can you please guide me on how to go about achieving this with binary numbers.

I’ve tried to run the code as given above but it returns and error `Warning: sprintf(): Too few arguments in…’

I do not claim to understand your objective, but the coding sequence rings a distant bell.

Does this have any bearing on your needs? (see the longer chart describing reflective Gray code below the short one)?

3 Likes