In C, you always have to worry about memory management. This still holds true when writing PHP extensions in C, but the extension API provides you with a safety net and some helpful debugging facilities if you use the API's memory-management wrapper functions (you are strongly encouraged to do so). The wrapper functions are:
emalloc( ) efree( ) estrdup( ) estrndup( ) ecalloc( ) erealloc( )
These work exactly like the native C counterparts after which they are named.
One of the features you get by using emalloc( ) is a safety net for memory leaks. If you emalloc( ) something and forget to efree( ) it, PHP prints a leak warning like this if you are running in debug mode (enabled by compiling PHP with the --enable-debug switch):
foo.c(123) : Freeing 0x0821E5FC (20 bytes), script=foo.php Last leak repeated 1 time
If you efree( ) something that was allocated using malloc( ) or some mechanism other than the PHP memory-management functions, you get the following:
--------------------------------------- foo.c(124) : Block 0x08219C94 status: Beginning: Overrun (magic=0x00000000, expected=0x7312F8DC) End: Unknown --------------------------------------- foo.c(124) : Block 0x0821EB1C status: Beginning: Overrun (magic=0x00000000, expected=0x7312F8DC) End: Unknown ---------------------------------------
In this case, line 124 in foo.c is the call to efree( ). PHP knows it didn't allocate this memory because it didn't contain the magic token that indicates a PHP allocation.
The emalloc( )/efree( ) safety net also catches overruns—e.g., if you emalloc(20) but write 21 bytes to that address. For example:
123: s = emalloc(6); 124: strcpy(s,"Rasmus"); 125: efree(s);
Because this code failed to allocate enough memory to hold the string and the terminating NULL, PHP prints this warning:
--------------------------------------- foo.c(125) : Block 0x08219CB8 status: Beginning: OK (allocated on foo.c:123, 6 bytes) End: Overflown (magic=0x2A8FCC00 instead of 0x2A8FCC84) 1 byte(s) overflown --------------------------------------- foo.c(125) : Block 0x08219C40 status: Beginning: OK (allocated on foo.c:123, 6 bytes) End: Overflown (magic=0x2A8FCC00 instead of 0x2A8FCC84) 1 byte(s) overflown ---------------------------------------
The warning shows where the overflowed memory was allocated (line 123) and where this overflow was detected (line 125 in the efree( ) call).
These memory-handling functions can catch a lot of silly little mistakes that might otherwise waste your time, so do your development with the debug switch enabled. Don't forget to recompile in non-debug mode when you are done testing, though, as the various tests done by the emalloc( ) type functions slow down PHP.
An extension compiled in debug mode does not work in an instance of PHP not compiled in debug mode. When PHP loads an extension, it checks to see if the debug setting, the thread-safety setting, and the API version all match. If something doesn't match, you will get a warning like this:
Warning: foo: Unable to initialize module Module compiled with debug=0, thread-safety=0 module API=20010901 PHP compiled with debug=1, thread-safety=0 module API=20010901
If you compile the Apache module version of PHP with the --enable-memory-limit switch, it will add the script's peak memory usage to the Apache r->notes table. You can access this information from other Apache modules, such as mod_log_config. Add this string to your Apache LogFormat line to log the peak number of bytes a script used:
%{mod_php_memory_usage}n
If you're having problems with a module allocating too much memory and grinding your system into the ground, build PHP with the memory-limit option enabled. This makes PHP heed the memory_limit directive in your php.ini file, terminating a script if it tries to allocate more memory than the specified limit. This results in errors like this:
Fatal error: Allowed memory size of 102400 bytes exhausted at ... (tried to allocate 46080 bytes) in /path/script.php on line 35
Copyright © 2003 O'Reilly & Associates. All rights reserved.