11 ms·
PHP's ob_start() pre-allocates 40k memory per call
- nknight 15y agoThe more usual solution for growable buffers is to start small and just double each time you hit the limit, not grow it by a static amount. People have tried a lot of different strategies, but there don't seem to be any that work much better for general purpose use.
- Someone 15y agoThis is not merely a matter of trying and picking what suits you best. If you grow a buffer by fixed amounts, you end up copying O(n^2) items. If you grow it by a fixed factor, you end up copying O(n) items. The difference can be staggering.
- jemfinch 15y agoYou only end up copying O(N^2) elements if you copy elements at all. You need not copy: you just keep a vector of pointers to your fixed buffers, a la GCC's deque implementation. That vector of pointers will be copied (and thus ought to grow by doubles), but each fixed buffer remains the same as the deque grows. I haven't looked at PHP's implementation, and I've long since learned not to expect intelligent, rational implementation decisions from that language community, but it's certainly possible to grow by a fixed amount and remain O(N) by never copying elements at all.
- jemfinch 15y agoDepending on the number of objects you're allocating, it's often better (for reduced fragmentation and smooth performance) to use an allocation strategy like GCC's std::deque: allocate fixed-size buffers, and use an exponentially growing array to hold pointers to those buffers. Once you start getting into millions of elements in your std::vector, you'll see long program pauses (as the vector grows and all the elements are copied to the new vector) and sometimes have difficulty finding a large enough contiguous buffer. This is one reason why the C++ cognoscenti recommend using std::deque as your default array-like container rather than std::vector.
- leif 15y agoWhy on earth are you trying to buffer 1-2K?
- CaveTech 15y agoBecause in PHP the return response begins as soon as you start non-buffered output, after which you can no longer modify headers, cookies, etc.
- wvenable 15y agoOf course, there's no reason to output everything all the time. It is possible to use string concatenation and output the result at the end of processing rather than 16 layers of ob_start(). That seems a bit excessive.
- itmag 15y agoI would think the BEST way in theory would be to not output strings at all but rather build some kind of logical representation via datastructures (ie a DOM tree as in JQuery or HTML templates which are tied to a code-behind as in ASP.NET) and then output that after all processing is done. What's the best PHP framework/library for that kind of thing?
- sirclueless 15y agoUmmm, all of them? The basic problem you run into is that PHP is basically a templating language at its heart. If you don't immediately open with a "<?" you start sending data. If you want to use PHP as it was originally intended -- as raw HTML with a smattering of dynamic bits in the middle -- without losing the ability to set headers, then ob_start makes sense. If on the other hand you want to use it in the way that most people do, you open with "<?php" and proceed to abuse a whole bunch of bastardized perl templating functions followed by an "echo $data; ?>" at the end of your source code. Now, given that PHP as a templating language is basically terrible, it's not that far out to just say, "To hell with PHP's native templating features, we're going to use our own!" but at that point you are already pretty far gone.
- bkrausz 15y agoIf I'm reading the PHP source correctly, in 5.4 this is changed to 16kb (this entire code block seems to have been rewritten): http://svn.php.net/viewvc/php/php-src/trunk/main/output.c?view=markup#l808 http://svn.php.net/viewvc/php/php-src/trunk/main/output.c?vi... http://svn.php.net/viewvc/php/php-src/trunk/main/php_output.h?view=markup#l82 http://svn.php.net/viewvc/php/php-src/trunk/main/php_output.... #define PHP_OUTPUT_HANDLER_DEFAULT_SIZE 0x4000
- ck2 15y agoI always treated output buffering/capturing like eval - if you have to use it, you need to question yourself carefully as to "why" and if there is a better way.
- forgotusername 15y agoAs any European user of HN knows too well, when you send tiny chunks separated by a few ms a time up to TCP, the majority of the planet will get a jittery half-rendered experience of your home page lasting seconds for a handful of actual kb downloaded. The better question might be "if you want to turn it off, the question is why", or something.
- ars 15y agoUsing one ob_start() could make sense for certain cases. But 16 of them? I can't think of any reason to nest ob_start 16 levels deep.
- masklinn 15y agoI'm thinking various components, each doing its own ob_start() for its output, something like that.
- Jach 15y agoMe neither, I'd be interested in the use case for that many. A few years ago I made a PHP-based template system that had one nested buffer to have a poor-man's eval of template (HTML with display-logic PHP) files, it just boiled down to: ob_start(); include $file; $contents = ob_get_contents(); ob_end_clean();
- lox 15y agoYup, this is common. If you put this in a function and use extract you can create a clean working space for a template where you can use $vars without worrying about polluting scope. I'd assume the 16x calls would be because they have a very complicated set of templates/layouts/partials, all doing their own templating.
- carldall 15y agoIt would surely be great if the PHP Docs would include such information right where the function is described.
- joelhaasnoot 15y agoIt's probably hidden somewhere in the comments from the last 10 years, next to the awful comments written in foreign languages.