Google Chrome version 89 began rolling out to users in the stable channel on March 2 and should be on most people’s machines by now. The new build offers significant memory savings on 64-bit Windows platforms thanks to increased use of Google’s PartitionAlloc memory allocator. On macOS, Chrome 89 plays catch-up and gets closer to the performance of the flagship Windows builds.
I feel like we get these reports and promises about Chrome’s performance every few months, yet Chrome keeps being the butt of jokes regarding its resource usage, especially on the Mac. Maybe this round will yield tangible improvements.
It’s been years since I coded but one of the essential tasks for the application/game framework I developed along with a virtual file system and other funky things was a memory allocator. I can barely remember what I did but reading through PartitionAlloc most of this seems familiar. I’m scratching my head about thread safe/thread unsafe. I think this was another object.
Nice work. This kind of thing should be standard. It’s why I liked using Borland C++ Builder and VCL.
Garbage collection can lead to much faster memory allocation: after all it is just incrementing a single pointer. However it comes at roughly 3x memory usage. (There was a paper on this using a modified Java runtime to measure effects of gc vs manual memory management). However C++ will probably never have native gc (except for shared/unique pointers).
Many projects then use special allocators. Protocol buffers, for example, implement a very simple version called Arenas: https://developers.google.com/protocol-buffers/docs/reference/arenas . Basically one “Arena” is used for allocating a forest of related objects, which are then free’d with a single call (instead of running thousands of small deallocations).
The topic is fascinating. This also has potential on faster execution due to cache locality. (A fragmented heap will make your O(1) memory access into O(logn)).
CppCon has sessions on memory allocations almost every year: https://www.youtube.com/watch?v=l14Zkx5OXr4, https://www.youtube.com/watch?v=LIb3L4vKZ7U . I would highly recommend those if you have the time.
sukru
Obviously whether GC is faster than alloc/free depends on the patterns of the program. Also the memory usage may or may not be significant. In the embedded world RAM can be very limited. On a normal PC if you start swapping, it can be annoying, if you’re in OOM killer territory it can be catastrophic.
I’ve never encountered google’s “arena” api, but the concept isn’t new and I agree with you that being able to allocate from a simple buffer and free it in one shot is extremely efficient, quite similar to the stack for that matter – assuming it fits the problem at hand.
Funnily enough the GC debate has come up before on osnews and some traditional C/C++ programmers are quite resistant to the idea that GCs ever perform better.
http://www.osnews.com/story/30892/fortran-is-still-a-thing/
I used to be in the GC camp, anti-GC camp, Java camp, C# camp, but then I realized all the tools have a purpose, and specific needs require different solutions.
Yes, being resistant to GC has slowed the adoption of some nicer choices in C++, but I think community have come to a nice compromise between RAII, smart pointers, and task specific memory managers.
sukru,
It’s interesting about the “camps”, I don’t feel like I’m attached to a camp…technology is just a tool. Yet some people become aggressively defensive about their favorite tools, it kind of reminds me of sport teams where people are so passionate about their team.
I mean, I use preeminently use a LAMP stack for work, but I don’t feel so attached that I have the need to defend it’s flaws or push it on others. I’m frequently bound by external project constraints that dictate the technology that I use.
I developed my own general purpose allocator once, and it performed favorably to glibc at the time with multithreaded workloads because the fast paths used lock free atomic primatives. I’m not sure how well it compares these days. Some times you don’t technically need dynamic heap allocation at all. A preallocated ring buffer/stack or similar structure may be near-optimal if you can use it. I haven’t done too much low level work recently, but a few years ago I did a lot of low level work interfacing with SDR hardware and I wrote my own buffer primitives to minimize locking&overhead. It was a fun project compared to web development.
Alfman,
” A preallocated ring buffer/stack or similar structure “…
I think that is a very common thing for Android games. Having a gc run at random times will break 60 fps performance, so they go for preallocated buffers.
Even Google seems to be recommending similar solutions:
https://www.youtube.com/watch?v=McAvq5SkeTk
sukru,
Indeed. As low level developers, often times we know when an object should be freed but the GC language provides no mechanism to do it and the only way to avoid GC is to use object pools. I remember doing this in java to try an speed things up, but I haven’t used this technique in a long time because I don’t use managed languages as much any more.
Computionally more sawwy people understand that all computation is always about balancing between CPU and RAM usage. Chrome is biased towards faster CPU operations by overloading RAM while Firefox is shit-slow while saving little bit more RAM. Which one do people bitch more about? Personally I’ve always rated Firefox subpar but of course everyone is allowed their own opinion.
sj87,
Yeah, there are many tradeoffs, which can be really specific to the project. For example a normalish PHP page will almost always be faster with garbage collection because it executes quickly and discards virtually all persistent state between runs, making it almost the ideal candidate for garbage collection. Other long running processes that keep lots of objects on the heap may be less efficient with garbage collection. A lot of languages that encourage a hands off approach to object allocation can end up overusing dynamic allocation on the heap when the stack would be far more efficient. Also some applications don’t lend themselves to a garbage collection interval, creating unwanted jitter in real time applications.
In terms of browsers, I tested this just now (not very scientific because I didn’t strip them down to stock) and actually found that firefox uses more ram than chrome opening up the same webpages.
PHP is actually very slow due to not preserving app state in between requests (properly, at least). The whole app has to be cold-booted and shutdown every time for a single request. There are some hacks to store some configs into memory and nowadays for preloading code files into memory to avoid parsing them at each boot but booting itself will have to occur still.
Considering PHP is one of the few languages that actually serve billion user systems (along with C++, Java, and maybe C#, Python, and Perl), they should be doing something right.
For example, take Wikipedia which is in top-5:
https://www.semrush.com/blog/most-visited-websites/
this is Wikimedia server stats:
https://grafana.wikimedia.org/d/000000605/datacenter-global-overview?orgId=1
They are serving ~8K QPS with ~100ms latency:
https://grafana.wikimedia.org/d/000000002/api-backend-summary?orgId=1&refresh=5m
Which is not too bad.
sukru,
Ironically PHP became popular before it became good. I think PHP was quite bad (yet still very popular) until around PHP 5 when they got serious about fixing it. Although there were lots of breaking changes so it was infuriating all the same, haha. One of the biggest mistakes compared to languages that had better planning is the global namespace and humorously inconsistent naming conventions.
sj87,
What you are describing sounds more like CGI, however the modern FPM application server doesn’t work that way. PHP runs in a big loop to handle continuously incoming requests non-stop, so it’s really not cold booting and shutting down each single request. Using the FPM application server, combined with PHP’s native compilation since 7.x, means PHP runs a lot faster than it used to.
Maybe I am misunderstanding you. If you are referring to the state information a PHP script loads in response to a web request, that typically does have to get read each request because the PHP program state is wiped clean with every request. Persistent state (like session variables) generally must be stored in the file system, database, or a cache engine like redis/varnish. It would be faster to store the information inside the PHP application process itself, but the main reason it isn’t is global consistency. If you consider that there can be many instances of the PHP application server running concurrently, making them stateless means that any PHP instance can processes your request.
I remember switching from the php cgi to the module in early 2000s. It was also the time where they stopped populating global variables with form fields. i.e.: you could no longer say
$username
but something like$HTTP_POST["username"]
(not 100% sure about syntax).After that they never stopped improving PHP.
sukru,
Yes, mod_php ran php directly within the apache process, but these days that is deprecated too over the lack of security isolation. At that time php was trying to enforce security isolation in userspace. It also imposed a multiprocess design on apache, which would become an obstacle to multi-threading and asynchronous handling. These days PHP runs under a dedicated process manager. I don’t think FPM was the first one, but it’s the one that’s included with PHP today.
https://www.php.net/manual/en/install.fpm.php
I like this approach because it’s decouples PHP from the webserver (ie apache) and works equally well with alternatives like nginx, not to mention it lets us run every website under different user accounts and the process manager is smart enough to spawn processes as needed.. I’m pretty happy with the way it works.
The application is the PHP code, not the interpreter. The PHP application has to load all configs, initialize services etc. separately for every single request, and then “shutdown” after every single request. The only way to optimize this is to generate complex caches of various kinds and manage them manually.
sj87,
A lot of PHP frameworks use PHP files to store the configuration, which is already precompiled and doesn’t have to be parsed/reloaded for every request. That comes for free and is fairly efficient to be honest. I personally wouldn’t use something like an XML file for configuration, but if you as a developer chose to do that, then yes you’d either have to parse it every request or save it in a cache, but I still think it’s reasonable.
I think stateless PHP pages is the best way to go, otherwise we open up a can of worms with the results being dependent on whichever PHP instance handles the request and whatever state it happens to contain. Session variables enable the programmer to explicitly save state whenever it’s desired. Consider the major benefit of this, since no other program state is persisted between pages, it means pages can be debugged independently of all other pages, which is a huge plus!
@Alfman
PHP is pretty much the only mainstream platform where there is no primary application instance that handles requests, instead booting a new instance for each and every request. Context handling isn’t all that difficult and all issues arise solely from bad application design.
This seems an artificial point. If you need to persist some state between requests, you will need to do it on all platforms, and you have to find means to do it. You already said that sometimes we store stuff into $_SESSION on PHP too, so then nothing is “stateless” anymore.
sj87,
PHP FPM does not boot a new instance for each and every request though, you’re using one instance to handle a large number of requests.
Yes, but in an arbitrarily large application the state can become extraordinarily complex. however it’s trivial to dump out the state contained by session variables.
It makes it easier to debug a PHP script when all persistent state is external to the script. I’m not saying it’s the only way to go, but I don’t think starting each page with empty state is bad.
@Alfman
Again I am talking about only the application written in PHP, not how the PHP interpreter itself is handled. There is no application state that exists in between requests, hence a new instance is always booted up for every request. This will mean that bootstrapping is also repeated for every single request. There is really no way around this, only to make it faster e.g. by those pre-compiled PHP file caches that you mentioned yourself previously.
Writing stateless code would fix this issue, though, and isn’t all that hard like I said before. Achieving proper code testability actually pretty much mandates this anyway. Only store state in as few places as possible, and preferably in an external service such as Redis.
sj87,
Ok, the wording is throwing me off track, sorry about that, haha.
Honestly most PHP sites I write don’t incur much bootup or termination costs, the overhead is primarily where you’d expect it to be, like file IO and database calls.
Do you have any data showing that application “bootstrapping” represents a huge overhead in general?
IMHO the efficiency of a framework overall plays a much bigger role than the fact it is using PHP’s stateless request model. I don’t deny that some popular PHP frameworks are absolutely awful. Take magento – the least efficient framework I have ever encountered. But even with that I’ve spend hours profiling it and the vast majority of overhead really is inside the script and not “bootstrapping”. Some programmers are just bad at optimizing and frequently they throw their crappy code behind a page cache and call it a day
So it’s kind of unclear why you object to PHP then? What exactly would you like it to have?
Maybe a specific example could help me understand what your concern is?
In principal there’s no reason you couldn’t create a stateful FCGI daemon in the language of your choice. I’ve actually done it with perl a long time ago, and it can probably be done with PHP. Basically instead of invoking your page’s handler function and returning, you’d write your own message loop like this.
Obviously you can make a stateful daemon and certain things could become faster, especially for mutable state so you don’t have to perform IPC, but it does make things more challenging to trivially scale out. And it’s in solving the scalability problem where having stateless pages really helps keep things simple. With stateless application servers scaling is simple. But once you start persisting state between requests, things like coherency, memory leaks, file handle leaks, session timeouts leaving objects in invalid states, etc can lead to unexpected results and persistent state corruption. You can “fix” it by restarting the service, but you may not know why it fixes it. One faulty page triggered by one request can potentially corrupt the state for all users. Well, a lot of these problems can be better contained in a stateless model where side effects don’t persist by design.
I’m curious what programming language you use for web development. I’m not altogether anti-state, but would you concede that state management could be more trouble than it’s worth for typical web programmers?
@Alfman
Of course in principle it is possible to write stateless PHP code. The problem is that most frameworks have ignored this design principle and have lots of state-dependent code in them. For example you cannot store anything into class variables or otherwise it will easily leak into other requests (from other users in other request contexts).
Setting a single request-dependent class variable in a shared service means that the service is now session-dependent and therefore not stateless anymore. Fixing these kinds of “design fuck-ups” requires probably at least two generations of framework releases; one to deprecate all the fuck-ups and another to remove them.
And since frameworks such as Symfony have dependencies to other major third-party libraries (e.g. Doctrine) that will also have to be rewritten, we can probably say that for Symfony getting rid of all stateful code means at least three to four major releases. They are releasing a new major release every two years so this means a delay of about 5+ years once somebody first starts pushing for this idea.
sj87,
Well, that’s a case of having one’s cake and eating it too. If you support the sharing of global variables between unrelated requests, those variables would clearly be accessible between unrelated requests. This may be desirable or it may not be, but I don’t see much utility for general web development to be honest. For the times that it does matter, I think it makes a lot of sense for the programmer to do it explicitly and just have no persistent or shared state by default. Otherwise there’s a serious risk of leaking data inappropriately.
I don’t think the benefit of a stateless design should be underestimated: it scales well and is trivial to run multiple PHP servers concurrently because they are stateless. I’m not strictly opposed to PHP having an option to support persistent state, but IMHO the shared resources that scripts have access to, like files, database, or redis cache, etc already handle these fairly well and the moment you add shared state to the application server you expose PHP developers to a litany of concurrency issues that have plagued software developers for ages. And IMHO the outcome would produce more bugs than benefit.
PHP applications aren’t stateless, that’s the point. They are full of stateful code in the wrong places and therefore statelessness must be emulated by rebooting the apps for every single request.
Obviously this description of matters is a bit reversed since this philosophy has been adopted based on the fact that all apps are always rebooted for every single request, so storing state in random places bears no significance.
Real stateless code can be executed as a single instance that handles multiple requests. Executing multiple instances of these kinds of applications is also trivial, just boot up however many instances you want and have a simple frontend instance proxy requests to these workers.
I’ve done this with Node.js apps and there are zero issues, and it scales massively better than any PHP app ever will.
Aside having cumbersome state-infested code, many libraries are also careless about memory management. Sometimes it is impossible to properly run a worker application because the libraries keep “leaking” memory (storing more and more stuff, never releasing any). This means that we will need additional management scripts that will reboot these workers just to make some sense with RAM usage.
So, PHP’s legacy of forced cold reboots is actually hampering application development in the modern ages. It has got nothing to do with true statelessness, it’s just a really dumb way for emulating it.
sj87,
I’m afraid I don’t understand your position at all. You started by complaining “PHP is actually very slow due to not preserving app state in between requests (properly, at least). The whole app has to be cold-booted and shutdown every time for a single request.” Now you’re complaining it’s full of stateful code in the wrong places. I for one don’t understand what you actually want it to do.
When was the last time you’ve used PHP? These things were solved a long time ago.
But PHP already does have “real stateless code” and the PHP PFM application server implements handling multiple requests efficiently. Look, I’m not trying to sell you on PHP, it’s not my favorite language by a long shot, but I can’t make heads or tails of this criticism. In any case my advice would be if you don’t like it, then don’t use it. Fair enough?
You should probably understand how PHP is different from all other platforms and why that makes PHP inherently worse. That is what I’m complaining about. It is suboptimal by default and the only trade-in is that careless developers can write shitty code without causing massive security issues on the side. (Sure, mildly hyperbolic.)
I’ve been writing PHP code for a living for about ten years now and another ten for fun before that, thank you very much. These problems are still very much present day, see for example Symfony documentation; topic “Don’t Let Workers Run Forever”:
https://symfony.com/doc/current/messenger.html#deploying-to-production
None of the mainstream PHP frameworks support writing proper stateless apps that could handle two consecutive requests without screwing up. You’d have to pretty much write your app from scratch if you wanted it to be able to do that.
PHP-FPM makes execution more efficient than prior to it, but it still cannot complete with the performance of having a constantly running app that doesn’t need to be bootstrapped on every request.
sj87,
I’m a professional developer too, I have experienced other platforms. I’m still unclear on what you object to that I’m saying. The fact that all state remains outside of the application server leads to very good scalability properties. Agreed? Keeping session state externally eliminates coherency issues, agreed?
There other ways to scale, sure, but with in-process storage you face new coherency issues as you bring up new instances. In principal a multithreaded program could do everything that multiprocess code can do and possibly do it more efficiently by eliminating process and IO overhead, but multithreaded programming is notorious for subtle bugs that creep in and are notoriously difficult to find as code complexity increases. So I don’t think the trade off is worth it for typical web developers.
If you prefer writing your own event loop in node.js and storing persistent state in global variables, that’s fine. But then you either have to give up trivial concurrency or coherency. This is the nature of the problem regardless of language.
node.js doesn’t support direct multithreading because the javascript language isn’t multithread safe. If you want parallelism, you have to rely on workers, and that’s fine but we should note that this creates new isolated javascript environments. We cannot manipulate shared structures across workers, so it shifts more towards the PHP model.
https://blog.logrocket.com/node-js-multithreading-what-are-worker-threads-and-why-do-they-matter-48ab102f8b10/
https://stackoverflow.com/questions/65202700/how-to-modify-global-variable-from-worker-thread-in-nodejs
I’m not pointing this out to complain about node.js, only to highlight that there’s no free lunch here, everything is a tradeoff.
Your link cites 3rd party code, this one to be specific.
https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/tutorials/getting-started.html
While I won’t contest that it might be leaky, faulting PHP for memory leaks in 3rd party code would be like faulting node.js for memory leaks in 3rd party code. 3rd party leaks are not the language’s fault! Anyways FPM makes it trivial to automatically spawn new instances after handling an arbitrary number of requests. And because PHP’s application server is stateless, you can restart it gracefully without any interruption to end users.
Can you name one that screws up? I agree that even with explicit state sharing, you can create buggy code, but it still seems to me that the opportunities for bugs is worse with implicit state sharing.
That’s the thing, you say this, but do you have any benchmarks to actually back that up?
https://webmobtuts.com/articles/php-vs-nodejs-comparison-and-benchmark/
I’m not trying to sell anybody on PHP, it really is not the best tool for everyone. There are pros and cons. For example I find node.js much more suitable for event oriented websockets applications than PHP is. But it does feel like at least some of the criticism is just unfair bias.