php-doc-en/reference/mysqlnd/memory.xml
Christoph Michael Becker 9e4c917c09 Fix other miscellaneous typos
Detected by codespell

Patch provided by tandre@php.net.


git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@349709 c90b9560-bf6c-de11-be94-00142212c4b1
2020-04-27 06:50:00 +00:00

155 lines
7.7 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<chapter xml:id="mysqlnd.memory" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Memory management</title>
<para>
<emphasis role="bold">Introduction</emphasis>
</para>
<para>
The MySQL Native Driver manages memory different than the MySQL Client Library.
The libraries differ in the way memory is allocated and released,
how memory is allocated in chunks while reading results from MySQL, which debug
and development options exist, and how results read from MySQL are linked to
PHP user variables.
</para>
<para>
The following notes are intended as an introduction and summary to users
interested at understanding the MySQL Native Driver at the C code level.
</para>
<para>
<emphasis role="bold">Memory management functions used</emphasis>
</para>
<para>
All memory allocation and deallocation is done using the PHP memory management
functions. Therefore, the memory consumption of mysqlnd can be tracked
using PHP API calls, such as <function>memory_get_usage</function>. Because memory is
allocated and released using the PHP memory management, the changes may not
immediately become visible at the operating system level. The PHP
memory management acts as a proxy which may delay releasing memory towards
the system. Due to this, comparing the memory usage of the MySQL Native Driver
and the MySQL Client Library is difficult. The MySQL Client Library
is using the operating system memory management calls directly, hence the effects
can be observed immediately at the operating system level.
</para>
<para>
Any memory limit enforced by PHP also affects the MySQL Native Driver. This
may cause out of memory errors when fetching large result sets that exceed
the size of the remaining memory made available by PHP. Because the MySQL
Client Library is not using PHP memory management functions, it does not comply
to any PHP memory limit set. If using the MySQL Client Library, depending on the
deployment model, the memory footprint of the PHP process may grow
beyond the PHP memory limit. But also PHP scripts may be able to process larger
result sets as parts of the memory allocated to hold the result sets are beyond
the control of the PHP engine.
</para>
<para>
PHP memory management functions are invoked by the MySQL Native Driver through
a lightweight wrapper. Among others, the wrapper makes debugging easier.
</para>
<para>
<emphasis role="bold">Handling of result sets</emphasis>
</para>
<para>
The various MySQL Server and the various client APIs differentiate
between <link linkend="mysqli.quickstart.statements">buffered and unbuffered</link>
result sets. Unbuffered result sets are transferred row-by-row from MySQL to the client
as the client iterates over the results. Buffered results are fetched
in their entirety by the client library before passing them on to the client.
</para>
<para>
The MySQL Native Driver is using PHP Streams for the network communication
with the MySQL Server. Results sent by MySQL are fetched from the PHP Streams
network buffers into the result buffer of mysqlnd. The result buffer is
made of zvals. In a second step the results are made available to the PHP script.
This final transfer from the result buffer into PHP variables impacts the memory
consumption and is mostly noticeable when using buffered result sets.
</para>
<para>
By default the MySQL Native Driver tries to avoid holding
buffered results twice in memory. Results are kept only once in the internal
result buffers and their zvals. When results are fetched into PHP variables
by the PHP script, the variables will reference the internal result buffers.
Database query results are not copied and kept in memory only once.
Should the user modify the contents of a variable holding the database results a
copy-on-write must be performed to avoid changing the referenced internal result
buffer. The contents of the buffer must not be modified because the user
may decide to read the result set a second time. The copy-on-write
mechanism is implemented using an additional reference
management list and the use of standard zval reference counters.
Copy-on-write must also be done if the user reads a result set into PHP variables and
frees a result set before the variables are unset.
</para>
<para>
Generally speaking, this pattern works well for scripts that read a
result set once and do not modify variables holding results. Its major drawback
is the memory overhead caused by the additional reference management which
comes primarily from the fact that user variables holding results
cannot be entirely released until the mysqlnd reference management
stops referencing them. The MySQL Native driver removes the reference to the
user variables when the result set is freed or a copy-on-write is performed.
An observer will see the total memory consumption grow until the result set
is released. Use the <link linkend="mysqlnd.stats">statistics</link> to check whether
a script does release result sets explicitly or the driver is does implicit
releases and thus memory is used for a time longer than necessary. Statistics
also help to see how many copy-on-write operations happened.
</para>
<para>
A PHP script reading many small rows of a buffered result set using a code snippet
equal or equivalent to <literal>while ($row = $res-&gt;fetch_assoc()) { ... }</literal>
may optimize memory consumption by requesting copies instead of references.
Albeit requesting copies means keeping results twice in memory, it allows
PHP to free the copy contained in <literal>$row</literal> as the result set
is being iterated and prior to releasing the result set itself. On a loaded server
optimizing peak memory usage may help improving the overall system performance
although for an individual script the copy approach may be slower due to
additional allocations and memory copy operations.
</para>
<para>
The copy mode can be enforced by setting
<link linkend="ini.mysqlnd.fetch_data_copy">mysqlnd.fetch_data_copy</link>=1.
</para>
<para>
<emphasis role="bold">Monitoring and debugging</emphasis>
</para>
<para>
There are multiple ways of tracking the memory usage of the MySQL Native Driver.
If the goal is to get a quick high level overview or to verify the memory efficiency
of PHP scripts, then check the <link linkend="mysqlnd.stats">statistics</link>
collected by the library. The statistics allow you, for example, to catch
SQL statements which generate more results than are processed by a PHP script.
</para>
<para>
The <link linkend="ini.mysqlnd.debug">debug</link> trace log can be configured to
record memory management calls. This helps to see when memory is allocated
or free'd. However, the size of the requested memory chunks may not be listed.
</para>
<para>
Some, recent versions of the MySQL Native Driver feature the emulation of
random out of memory situations. This feature is meant to be used by the
C developers of the library or mysqlnd <link linkend="mysqlnd.plugin">plugin</link>
authors only. Please, search the source code for corresponding PHP configuration
settings and further details. The feature is considered private and may be
modified at any time without prior notice.
</para>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->