r/PHP•
jgmdev

PHP array implementation that consumes 10x less memory

Here I'm sharing something that I toyed with some long time ago but never shared and found interesting, which is a pure php implementation data structure for arrays that can consume up to 10x less ram than native one:

https://github.com/jgmdev/lessram

Posted Jul 10, 2019, 1:59 AM UTC

4560
colshrapnel•

Did you try Judy?

41
godsdead•

TIL about Judy

16
jgmdevOP•

This is another great extension that would be nice to test: https://github.com/php-ds/ext-ds

3
rtheunissen•

27 comments

Ds\Vector uses ~50% as much memory, and Ds\Map using the same amount (but supports objects as keys). Not nearly 10x, but not slower either. Really depends on what you want to optimize for.

1
jgmdevOP•

Nice! would be interesting to have some script that benchmarks Spl, Judy and Ds extensions, would be really informative.

1
2012-09-04•

Dammit. I maybe wouldn't have wasted all that time porting some software to HackLang if I had known about this :-/

2
PetahNZ•

Woo 10x less memory (actually only ~5x by my tests), but about ~32x times slower. Not sure if its worth it. \

Also it throws a lot of `Notice: Uninitialized string offset: 4607500 in C:\work\lessram\bench.php on line 440` errors.

33
jgmdevOP•

Fixed the notices and improved serialize/unserialize peformance, but can't do anything about Windows performance :(, also notice that when storing arrays it does takes 10x less ram, not trying to exaggerate here :)

3
jgmdevOP•

I'm testing on linux, maybe something in windows is slower (usually php code is slower on windows). And good catch on the error, I have notices disabled, will fix later.

2
CarefulMouse•

I wonder if they compiled it with Zephir it might be more viable?

Assuming it keeps the same memory consumption benefit while improving speed from being compiled C?

EDIT: Actually I doubt that would help much now that I've looked over the sauce.

1
un-glaublich•

Worth it? Isn't that the whole point of the memory / performance balance... It depends wholly on your situation whether this is worth it.

1
systematical•

So reading the benchmark results, it has a smaller footprint at the expense of CPU, right? Just making sure I am reading that correctly.

8
nvahalik•

The code trades off faster native storage for storing everything as a string. So while the memory footprint is lower, you now have to do a ton of string operations.

2
DrWhatNoName•

hmmm, I dont see a real use for this in live applications. As we are mostly needing response time for web app.

But this could help in cron jobs, queues and some microservices which dont have a user waiting on the other side and which might be working with large amounts of data.

​

But as other comments have mentioned, your implimentation is more error prone and is missing checks native has and are required.

8
jgmdevOP•

Added missing checks to prevent overflows reported when having E_NOTICE enabled, but... maybe some more checks are needed :)

2
WarInternal•

Honestly if I'm working with large data sets I prefer iterators and generators instead. They don't have the unbounded memory issue thay arrays do. You work with one item at a time and GC is free to clean up as it goes.

1
Ravavyr•

Technically for frontend stuff, you should be caching, so the code shouldn't be executing on every single page load. Although i know many many many sites do this anyway.

-6
DrWhatNoName•

uhh what...

4
Ravavyr•

Your PHP shouldn't be executing on every page load if you're caching the pages you are rendering. You cache the HTML output so you reduce/eliminate most of the heavy lifting done by PHP and rebuild those cached files as needed only.

0†
apennypacker•

Most modern, dynamic applications are going to have a lot of dynamic stuff going on that will not cache well. Of course, if you are serving up static pages, cache away.

2
DrWhatNoName•

Ya no, thats not how websites function dude.

0
Engival•

If you're going to do something like this, why not create a C module plugin to meet your goal and not have such horrible performance.

7
Ravavyr•

That implies the devs know both PHP and C and longterm maintenance becomes more work. Easier to keep it all in one language, one code base?

5
wh33t•

Not sure why you got downvoted. Seems like a legit issue to me.

3
Ravavyr•

People have opinions, especially backenders, strong strong opinions about what a "real dev" should know. ;)

4
wh33t•

Yiiiiip, thats my take on it as well. Like if time, maintenance, the search for talent, budget and simplicity aren't issues why even use such a high level language as C to write your server side scripts, just use assembler! /s

1
Engival•

Maintenance is certainly a legit issue. I would also consider using some weird class to manage an array is also a maintenance issue. If you want pure standard PHP, then use PHP's arrays.

1
carlos_vini•

I think this post might be interesting for people who think PHP arrays are not enough for their use cases: https://medium.com/@rtheunissen/efficient-data-structures-for-php-7-9dda7af674cd

6
ThraShErDDoS•

But look at how much slower it is...

5
rtheunissen•

Usually you would trade memory for speed. Memory is cheap, time is expensive. Optimizing for memory, especially in the context of PHP, feels backwards to me. Was this motivated by a problem or more "for science"?

4
jgmdevOP•

I would say that both, sometime ago I was working on a project that needed to load lots of data and the php script went out of memory so I had to modify the php.ini file to increase memory. When learning about the zend engine (while developing a PHP extension) I saw how huge zval variables where and how much data they needed to represent each value, so I thought, "real ram is similar to an array of char*", so storing everything in a string is similar to dealing with ram and wanted to see how it performed... Maybe porting the logic directly to C would yield better performance, it is up to how fast C string functions and realloc are.

2
mcfogw•

Interesting tech for some edge case. How about optional gzip to save more ram? Also should be compared with Spl data structure classes like FixedArray

2
jgmdevOP•

The gzip option is actually a good idea! And testing against FixedArray would be a simple modification to bench.php

3
jgmdevOP•

Added SplFixedArray and gzdeflate test to php native arrays and SplFixedArray. Hint: SplFixedArray consumes more ram and is slower than native php array.

2
justaphpguy•

You should not need the `Autoloader` at all.

In `bench.php` you should include `vendor/autoload.php`

2
ThatWall•

I can't imagine this implementation would be suitable for all cases. This implementation seems best for lots of scalar data. Storing objects (like a collection) with this implementation means they loose reference.

How is utf8 support? I noticed the strlen call to check for length to set the index.

1
[deleted]•

[deleted]

2
jgmdevOP•

strlen is binary safe so it should work with any data, utf8 stores everything as a char.

Edit: good call on the objects, they will surely loose reference

1
codemunky•

Then why does http://php.net/mb_strlen exist?

1
jgmdevOP•

Because strlen knows how to count bytes but in utf8 more than 1 byte could represent a single letter, that is why you need mb_* functions which can distinguish a character that needs 2 bytes to be represented. In this case there is no need to count amount of letters but the total amount of bytes which strlen handles properly.

1
johannes1234•

What might be interesting for people seeing this are SPL Data structures: https://www.php.net/manual/en/spl.datastructures.php

They are not built around PHP's mutant hashtables (which are not only hashtables, but also linked lists and have some indexing magic and so on) but more basic data structures therefore can in some scenarios be more efficient, while less flexible. With PHP 7 the benefit became smaller, but is still there.

In the past there were also pure PHP implementations of those for reference, which have been removed for reasons I don't understand: https://github.com/php/php-src/commit/80c6ba26e3fe83174a0e7dce367d8a39aa093ae1

1
rtheunissen•

There is actually zero benefit in PHP 7+, until someone reworks the SPL data structures. I tried my best to explain that here but will do more analysis when 2.0 is finished.

3
Sarke1•

Might as well save it to disk and save all the ram.

1
jgmdevOP•

That could actually be slower because of disk I/O and PHP overhead on file functions, but who knows what can happen with a speedy SSD and kernel caching.

1
Sarke1•

My point is that if you're gonna sacrifice speed for RAM, you can just go all out.

Next step after that is a database.

1
chsxf•

I've made some tests on my own on your code (tested on macOS 10.14).

With strings, it consumes 4 to 5 times less memory, not 10x. It is when storing arrays that you get the 10x benefit.

Timings are very disappointing. We're talking a factor of 6 to 30 times slower than native PHP array management. You definitely have to optimize that, even if the purpose is just to load a huge bunch of data.

However, I've checked the peak memory usage by dividing your benchmark in individuel tests and the gap is lower in this scenario (3 to 4x less memory with strings, 5 to 6x with arrays). I think it is the true metric to look at as it will require that amount of memory from your server when your code will run (not just a certain quantity once the job is done).

My results:

Peak usage:
memory_get_peak_usage(false / true)

String
======
- Static: 114 / 118 MB (2.54x less mem)
- Dynamic: 73 / 76 MB (3.94x less mem)
- Native: 299 / 300 MB

Array
=====
- Static: 224 / 227 MB (5x less mem)
- Dynamic: 181 / 184 MB (6.16x less mem)
- Native: 1132 / 1135 MB
1
jgmdevOP•

With 10x, yes I was referring to arrays. Interesting results, I'm curious on what data you stored on the structures. Maybe memory_get_peak_usage isn't that reliable... And the only way to further optimize this would be to port the algorithm to C and test how fast are native C string functions without the PHP overhead and the realloc call (which would be needed to increase the char* containing the data). Then write a php extension wrapper over the C algorithms.

1
chsxf•

I've used your bench.php, but sliced it to run the tests individually and not sequencially (as memory_get_peak_usage() gives only the maximum memory level for a single run). So I use the very same data as you do.

1
2012-09-04•

Once JIT hits, this will give the internals guys a run for their money!!!

-1
dont_ban_me_please•

A+ for creativity.

.. storing an array as a string lolol

-2
Ravavyr•

JSON? but everyone loves that one :)

2
dont_ban_me_please•

I guess, more clearly, storing it in memory as a string, no one does that.

1
jgmdevOP•

if you think about it, it is not a string but an array of bytes... A string internally on PHP and C (of course) is represented as char* which is equivalent to char[] and char represents a single byte, even your computer ram works similarly, but it is much more efficient because it uses memory addresses to retrieve data which is faster.

2
[deleted]•

[removed]

-6
SurgioClemente•

Why is that even a sub...

6