2

Consider this code:

$position = ...
$data = substr($data, 0, $position) . $insertion . substr($data, $position);

Normally $data in the case of the script being discussed is no larger than 2-3 MB. But it happened that a user who would like to use the script tried to use it for $data with the size of about 17 MB and got

PHP Fatal error:  Allowed memory size of 33554432 bytes exhausted (tried to allocate 17687776 bytes) in //index.php on line 179'

where line 179 is the second one shown above ($data = ...), 33554432 bytes = 32 MB and 17687776 > 16 MB. Now I'm assuming that the problem is memory is allocated for both $data and substr($data, 0, $position) and substr($data, $position). I'm aware of the memory limit and suggested them to try to increase it. However, I wonder if I can optimize this so that we don't need the memory limit to be more than twice larger than $data.

So my question is: is there some clever way to insert $insertion to minimize memory usage? (not to store $data in memory twice) How about the case where substr($data, $position) is relatively small?

YakovL
  • 7,557
  • 12
  • 62
  • 102

1 Answers1

4

Your current implementation depends on target position. It most memory-efficient if the position near to end of data. Worst case is inserting into begin of the data.

Mini-benchmark for example:

$data      = str_repeat('abcde', 500000);
$insertion = 'abc';
$position  = 0;

$data = substr($data, 0, $position) . $insertion . substr($data, $position);

echo memory_get_peak_usage(), "\n";

Script above show peak usage is 7868728 bytes (on my machine). If I set the $position = strlen($data) / 2 then it prints 6619424. If append the string at the end of data ($position = strlen($data)) then it prints 5365720.

(Update: memory consumption of code above also depends on the PHP version)

But PHP already has efficient function for replace text within a portion of a string: substr_replace():

$data = substr_replace($data, $insertion, $position, 0);

In all cases, this requires as much memory as the implementation above (through concatenation of substr() results) in best case.

Timurib
  • 2,735
  • 16
  • 29
  • Thanks, this is very helpful indeed, especially the way to test (using `memory_get_peak_usage()`), but I got some controversial results of tests, so I'll accept the answer later when I'm sure all this is correct (actually, I'm looking for *why* and have to get a more detailed picture). Definitely upvoted. – YakovL Aug 25 '17 at 18:41
  • 1
    Oh, you are right! https://3v4l.org/UV3Is - looks like memory consumption in this case also depends on version of PHP (may be latest version has some related optimizations?). Thanks, I have edited the answer. – Timurib Aug 27 '17 at 19:04
  • Nice! Needed Memory is the same, but substr_replace is twice as fast. (benchmark for script time) – Taurus Oct 18 '22 at 14:28