国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
PHP V5.2 中的新增功能,第 1 部分: 使用新的內(nèi)存管理器

PHP V5.2:開始

2006年 11 月發(fā)布了 PHP V5.2,它包括許多新增功能和錯(cuò)誤修正。它廢止了 5.1 版并被推薦給所有 PHP V5用戶進(jìn)行升級(jí)。我最喜歡的實(shí)驗(yàn)室環(huán)境 —— Windows®、Apache、MySQL、PHP (WAMP) —— 已經(jīng)被引入了 V5.2的新軟件包中(請(qǐng)參閱 參考資料)。您將在那里找到在 Windows® XP 或 2003 計(jì)算機(jī)上安裝 PHP V5.2、MySQL 和 Apache 的應(yīng)用程序。您可以十分輕松地進(jìn)行安裝,它有很多不錯(cuò)的小的管理優(yōu)點(diǎn),并且我十分誠懇地推薦使用它。

雖然對(duì)于 Windows 用戶來說,這是最簡單的軟件包,但是在 Linux 上配置 PHP 時(shí)您需要添加以下代碼:--memory-limit-enabled(適用于您服務(wù)器的任何其他選項(xiàng)除外)。不過,在 Windows 下,提供了一個(gè)解決此問題的函數(shù)。

PHP V5.2 中有很多改進(jìn)之處,并且一個(gè)至關(guān)重要的領(lǐng)域是內(nèi)存管理。從 README.ZEND_MM 中準(zhǔn)確地引述就是:“新內(nèi)存管理器(PHP5.2 以及更高版本)的目標(biāo)是減少內(nèi)存分配開銷并加速內(nèi)存管理。”

下面是 V5.2 發(fā)行說明中的一些關(guān)鍵內(nèi)容:

  • 刪除了不必要的 --disable-zend-memory-manager 配置選項(xiàng)
  • 添加了 --enable-malloc-mm 配置選項(xiàng),調(diào)試構(gòu)建時(shí)此配置選項(xiàng)將被默認(rèn)啟用以允許使用內(nèi)部和外部內(nèi)存調(diào)試程序
  • 允許使用 ZEND_MM_MEM_TYPEZEND_MM_SEG_SIZE 環(huán)境變量調(diào)整內(nèi)存管理器

為了理解這些新增功能的含義,我們需要深入研究內(nèi)存管理中的藝術(shù),并考慮為什么分配開銷和運(yùn)行速度是大問題。





回頁首


為什么進(jìn)行內(nèi)存管理?

計(jì)算中開發(fā)最快速的一項(xiàng)技術(shù)是內(nèi)存和數(shù)據(jù)存儲(chǔ),它們是受不斷增加速度和存儲(chǔ)大小這樣持續(xù)的需求而驅(qū)動(dòng)的。早期的計(jì)算機(jī)使用卡作為內(nèi)存,然后轉(zhuǎn)向了芯片技術(shù)。您能想象在只有 1 KB RAM內(nèi)存的計(jì)算機(jī)工作的情景嗎?很多早期的計(jì)算機(jī)程序員就曾使用過。這些先驅(qū)者很快就意識(shí)到,要在技術(shù)限制下工作,他們將必須細(xì)心地用瑣碎的命令避免系統(tǒng)過載。

身為 PHP 開發(fā)人員,與使用 C++或其他更嚴(yán)格的語言編碼的同事相比,我們所在的環(huán)境更方便進(jìn)行編碼。在我們的世界里,我們自己不必?fù)?dān)心如何處理系統(tǒng)內(nèi)存,因?yàn)?PHP將為我們處理這個(gè)問題。但是,在其他編程領(lǐng)域里,負(fù)責(zé)任的編碼人員將使用各種函數(shù)確保執(zhí)行的命令不會(huì)覆蓋其他一些程序數(shù)據(jù) ——因而,破壞了程序的運(yùn)行。

內(nèi)存管理通常是由來自編碼人員的請(qǐng)求處理的,以分配和釋放內(nèi)存塊。分配塊 可以保存任何類型的數(shù)據(jù),并且此過程將為該數(shù)據(jù)隔開一定量的內(nèi)存,并當(dāng)操作需要訪問數(shù)據(jù)時(shí)為應(yīng)用程序提供訪問方法。人們期望程序在完成任何操作后釋放分配的內(nèi)存,并允許系統(tǒng)和其他程序員使用該內(nèi)存。如果程序沒有把內(nèi)存釋放回系統(tǒng),則稱為內(nèi)存泄露

泄露是任何運(yùn)行程序都存在的普遍問題,并且某種程度內(nèi)通常是可以接受的,尤其是當(dāng)我們知道運(yùn)行程序?qū)⒘⒓唇K止并釋放默認(rèn)分配給程序的所有內(nèi)存。

由于隨機(jī)運(yùn)行和終止程序,像幾乎所有客戶機(jī)應(yīng)用程序一樣,這是個(gè)問題。期望服務(wù)器應(yīng)用程序不確定地運(yùn)行而不終止或重新啟動(dòng),這使得內(nèi)存管理對(duì)于服務(wù)器守護(hù)程序編程絕對(duì)的至關(guān)重要。在長時(shí)間運(yùn)行的程序中,即使一個(gè)小的泄露最后都將發(fā)展為系統(tǒng)衰弱問題,因?yàn)閮?nèi)存塊已被使用并且永遠(yuǎn)不被釋放。





回頁首


長期考慮

正如使用任何語言編寫一樣,用 PHP 編寫的永久性服務(wù)器守護(hù)程序有很多可能的用途。但是當(dāng)我們出于這些目的開始使用 PHP 時(shí),我們也必須考慮內(nèi)存使用情況。

解析大量數(shù)據(jù)或可能隱藏?zé)o限次循環(huán)的腳本都趨于消耗大量內(nèi)存。很明顯,一旦內(nèi)存被耗盡,服務(wù)器的性能就降低,因此在執(zhí)行腳本時(shí)我們還必須注意內(nèi)存的使用情況。雖然我們可以通過啟用系統(tǒng)監(jiān)視器來簡單觀察內(nèi)存的使用量,但是它不會(huì)告訴我們比整個(gè)系統(tǒng)內(nèi)存狀態(tài)更有用的任何內(nèi)容。有時(shí)我們不止需要幫助進(jìn)行故障檢修或優(yōu)化的內(nèi)容,而有時(shí)我們只是需要更多詳細(xì)信息。

獲得腳本執(zhí)行內(nèi)容的透明性的一種方法是使用內(nèi)部或外部調(diào)試器。內(nèi)部調(diào)試器 是呈現(xiàn)為執(zhí)行腳本的相同的進(jìn)程。從操作系統(tǒng)的角度考慮的獨(dú)立進(jìn)程是外部調(diào)試器。使用調(diào)試器進(jìn)行內(nèi)存分析類似于任何一種情況,但是使用了不同的方法訪問內(nèi)存。內(nèi)部調(diào)試器對(duì)運(yùn)行進(jìn)程所在的內(nèi)存空間具有直接訪問權(quán),而外部調(diào)試器將通過套接字訪問內(nèi)存。

有許多方法和可用的調(diào)試服務(wù)器(外部)和庫(內(nèi)部)可用于輔助開發(fā)。為了準(zhǔn)備好對(duì) PHP 安裝進(jìn)行調(diào)試,可以使用新提供的 --enable-malloc-mm,它在 DEBUG 構(gòu)建中默認(rèn)被啟用。這使環(huán)境變量 USE_ZEND_ALLOC 可用于允許在運(yùn)行時(shí)選擇 mallocemalloc 內(nèi)存分配。使用 malloc-type 內(nèi)存分配將允許外部調(diào)試器觀察內(nèi)存使用情況,而 emalloc 分配將使用 Zend 內(nèi)存管理器抽象,要求進(jìn)行內(nèi)部調(diào)試。





回頁首


PHP 中的內(nèi)存管理函數(shù)

除了使內(nèi)存管理器更靈活更透明之外,PHP V5.2 還為 memory_get_usage()memory_get_peak_usage() 提供了一個(gè)新參數(shù),這兩個(gè)函數(shù)允許查看內(nèi)存使用量。說明中提及的新布爾值是 real_size。通過調(diào)用函數(shù) memory_get_usage($real);(其中 $real = true),結(jié)果將為調(diào)用時(shí)系統(tǒng)中實(shí)際分配的內(nèi)存大小,包括內(nèi)存管理器開銷。如果不使用標(biāo)記組,則返回的數(shù)據(jù)將只包括在運(yùn)行腳本內(nèi)使用的內(nèi)存,減去內(nèi)存管理器開銷。

memory_get_usage()memory_get_peak_usage() 的不同之處在于后者將返回到目前為止調(diào)用它的運(yùn)行進(jìn)程的最高內(nèi)存量,而前者只返回執(zhí)行時(shí)的使用量。

對(duì)于 memory_get_usage(),php.net 提供了清單 1 中的代碼片段。


清單 1. memory_get_usage() 示例
                
<?php

// This is only an example, the numbers below will
// differ depending on your system

echo memory_get_usage() . "\n"; // 36640
$a = str_repeat("Hello", 4242);
echo memory_get_usage() . "\n"; // 57960
unset($a);
echo memory_get_usage() . "\n"; // 36744

?>

在這個(gè)簡單示例中,我們首先回轉(zhuǎn)了直接調(diào)用 memory_get_usage() 的結(jié)果,代碼注釋中顯示可能在作者的系統(tǒng)中有 36640 字節(jié)的常見結(jié)果。然后我們使用 4,242 個(gè) “Hello” 副本來裝載 $a 并再次運(yùn)行函數(shù)。圖 1 中可以看到此簡單應(yīng)用的輸出。


圖 1. memory_get_usage() 的示例輸出


沒有 memory_get_peak_usage() 的示例,因?yàn)閮烧呤窒嗨?,語法是相同的。但是,對(duì)于清單 1 中的示例代碼,將只有一個(gè)結(jié)果,即當(dāng)時(shí)的最高內(nèi)存使用量。讓我們看一看清單 2。


清單 2. memory_get_peak_usage() 示例
                
<?php

// This is only an example, the numbers below will
// differ depending on your system

echo memory_get_peak_usage() . "\n"; // 36640
$a = str_repeat("Hello", 4242);
echo memory_get_peak_usage() . "\n"; // 57960
unset($a);
echo memory_get_peak_usage() . "\n"; // 36744

?>

清單 2 中的代碼跟圖 1 一樣,但是 memory_get_usage() 已經(jīng)替換為 memory_get_peak_usage()。在我們用 4242 個(gè) “Hello” 副本填充 $a 之前,輸出都不會(huì)有多大更改。內(nèi)存跳升至 57960,表示到目前為止的峰值。當(dāng)檢查內(nèi)存使用量峰值時(shí),得到了目前為止的最高值,因此所有進(jìn)一步調(diào)用都將得到 57960,直至我們處理的操作比處理 $a 使用的內(nèi)存更多(參見圖 2)。


圖 2. memory_get_peak_usage() 的示例輸出






回頁首


限制內(nèi)存使用

確保托管應(yīng)用程序的服務(wù)器不過載的一種方法是限制 PHP 執(zhí)行的任何腳本使用的內(nèi)存量。這根本不是我們應(yīng)當(dāng)執(zhí)行的操作,但由于 PHP是一種松散類型的語言,并且是在運(yùn)行時(shí)解析的,因此我們有時(shí)會(huì)獲得在釋放到生產(chǎn)應(yīng)用程序中后編寫得很差的腳本。這些腳本可能執(zhí)行循環(huán),也可能打開一張長的文件列表,忘記在打開新文件之前先關(guān)閉當(dāng)前文件。無論在哪一種情況下,編寫很差的腳本可能在您知道之前以消耗大量內(nèi)存告終。

在 PHP.INI 中,您可以使用配制參數(shù) memory_limit 來指定任何腳本能夠在系統(tǒng)中運(yùn)行的最大內(nèi)存使用量。這不是對(duì)于 V5.2 的特定更改,但是內(nèi)存管理器及其使用的任何討論都值得至少快速查看一次這個(gè)特性。它還精心地引導(dǎo)我使用內(nèi)存管理器的最后幾個(gè)新功能:環(huán)境變量。





回頁首


調(diào)整內(nèi)存管理器

最后,在不能做完美主義者但是又完全符合自己目的的情況下怎樣編程?新環(huán)境變量 ZEND_MM_MEM_TYPEZEND_MM_SEG_SIZE 正好可以滿足您的需求。

當(dāng)內(nèi)存管理器分配大型內(nèi)存塊時(shí),它是安裝 ZEND_MM_SEG_SIZE變量中列出的預(yù)定大小執(zhí)行操作的。這些內(nèi)存塊的默認(rèn)分區(qū)大小為每塊 256KB,但是您可以調(diào)整這些分區(qū)大小以滿足特殊需求。例如,如果您注意到最常用的一個(gè)腳本中的操作導(dǎo)致大量的內(nèi)存浪費(fèi),則可以將此大小調(diào)整為更接近匹配腳本需求的值,減少分配的內(nèi)存量但剩下的內(nèi)存量仍然為零。在正確的條件下,此類謹(jǐn)慎的配制調(diào)整可能造成巨大差別。





回頁首


在 Windows 中檢索內(nèi)存使用情況

如果具有預(yù)構(gòu)建的 PHP Windows 二進(jìn)制代碼,而沒有在構(gòu)建時(shí)使用 --enable-memory-limit 選項(xiàng),則需要先瀏覽此部分然后再繼續(xù)。對(duì)于 Linux®,配置 PHP 構(gòu)建時(shí)用 --enable-memory-limit 選項(xiàng)構(gòu)建 PHP。

要使用 Windows 二進(jìn)制代碼檢索內(nèi)存使用情況,請(qǐng)創(chuàng)建以下函數(shù)。


清單 3. 在 Windows 下獲得內(nèi)存使用情況
                
<?php

function memory_get_usage(){
$output = array();
exec(‘tasklist /FI "PID eq ‘.getmypid().‘" /FO LIST‘, $output );
return preg_replace( ‘/[^0-9]/‘, ‘‘, $output[5] ) * 1024;
}

?>

將結(jié)果保存到名為 function.php 的文件?,F(xiàn)在您只能將此文件包含在需要使用它的腳本中。





回頁首


動(dòng)手實(shí)踐

讓我們來看一看使用這些設(shè)置的實(shí)際示例給我們帶來的好處??赡苡泻芏啻文枷胫罏槭裁丛谀_本的末尾沒有正確分配內(nèi)存。原因是因?yàn)橐恍┖瘮?shù)本身導(dǎo)致了內(nèi)存泄露,尤其是在僅使用內(nèi)置 PHP 函數(shù)的情況下。在這里,您將了解如何發(fā)現(xiàn)此類問題。并且為了開始進(jìn)行內(nèi)存泄露查找的征戰(zhàn),您將創(chuàng)建一個(gè)測(cè)試MySQL 數(shù)據(jù)庫,如清單 4 所示。


清單 4. 創(chuàng)建測(cè)試數(shù)據(jù)庫
                
mysql> create database memory_test;

mysql> use memory_test;

mysql> create table leak_test
( id int not null primary key auto_increment,
data varchar(255) not null default ‘‘);

mysql> insert into leak_test (data) values ("data1"),("data 2"),
("data 3"),("data 4"),("data 5"),("data6"),("data 7"),
("data 8"),("data 9"),("data 10");

這將創(chuàng)建一個(gè)帶有 ID 字段和數(shù)據(jù)字段的簡單表。

在下一張清單中,想象我們堅(jiān)韌不拔的程序員正在執(zhí)行一些 MySQL 函數(shù),特別是使用 mysql_query() 將結(jié)果應(yīng)用到變量。當(dāng)他這樣做時(shí),他將注意到即使調(diào)用 mysql_free_result(),一些內(nèi)存也不會(huì)被釋放,導(dǎo)致內(nèi)存使用量隨著 Apache 進(jìn)程不斷增長(參見清單 5)。


清單 5. 內(nèi)存泄露檢測(cè)示例
                
for ( $x=0; $x<300; $x++ ) {
$db = mysql_connect("localhost", "root", "test");
mysql_select_db("test");
$sql = "SELECT data FROM test";
$result = mysql_query($sql); // The operation suspected of leaking
mysql_free_result($result);
mysql_close($db);
}

清單 5 是在任何位置都可能使用的簡單 MySQL 數(shù)據(jù)庫操作。在運(yùn)行腳本時(shí),我們注意到一些與內(nèi)存使用量相關(guān)的奇怪行為并需要將其檢查出來。為了使用內(nèi)存管理函數(shù)以使我們可以檢驗(yàn)發(fā)生錯(cuò)誤的位置,我們將使用以下代碼。


清單 6. 定標(biāo)查找錯(cuò)誤的示例
                
<?php

if( !function_exists(‘memory_get_usage‘) ){
include(‘function.php‘);
}

echo "At the start we‘re using (in bytes): ",
memory_get_usage() , "\n<br>";

$db = mysql_connect("localhost", "user", "password");
mysql_select_db("memory_test");

echo "After connecting, we‘re using (in bytes): ",
memory_get_usage(),"\n<br>";

for ( $x=0; $x<10; $x++ ) {
$sql =
"SELECT data FROM leak_test WHERE id=‘".$x."‘";
$result = mysql_query($sql); // The operation
// suspected of leaking.
echo "After query #$x, we‘re using (in bytes): ",
memory_get_usage(), "\n<br>";
mysql_free_result($result);
echo "After freeing result $x, we‘re using (in bytes): ",
memory_get_usage(), "\n<br>";
}

mysql_close($db);
echo "After closing the connection, we‘re using (in bytes): ",
memory_get_usage(), "\n<br>";
echo "Peak memory usage for the script (in bytes):".
memory_get_peak_usage();

?>

注:按照定義的時(shí)間間隔檢查當(dāng)前內(nèi)存使用量。在下面的輸出中,通過顯示我們的腳本一直在為函數(shù)分配內(nèi)存,并且在應(yīng)當(dāng)釋放的時(shí)候沒有釋放內(nèi)存,從而提供對(duì)內(nèi)存泄露的實(shí)際測(cè)試,您可以看到每次調(diào)用時(shí)內(nèi)存使用量如何增長。


清單 7. 測(cè)試腳本輸出
                
At the start we‘re using (in bytes): 63216
After connecting, we‘re using (in bytes): 64436
After query #0, we‘re using (in bytes): 64760
After freeing result 0, we‘re using (in bytes): 64828
After query #1, we‘re using (in bytes): 65004
After freeing result 1, we‘re using (in bytes): 65080
After query #2, we‘re using (in bytes): 65160
After freeing result 2, we‘re using (in bytes): 65204
After query #3, we‘re using (in bytes): 65284
After freeing result 3, we‘re using (in bytes): 65328
After query #4, we‘re using (in bytes): 65408
After freeing result 4, we‘re using (in bytes): 65452
After query #5, we‘re using (in bytes): 65532
After freeing result 5, we‘re using (in bytes): 65576
After query #6, we‘re using (in bytes): 65656
After freeing result 6, we‘re using (in bytes): 65700
After query #7, we‘re using (in bytes): 65780
After freeing result 7, we‘re using (in bytes): 65824
After query #8, we‘re using (in bytes): 65904
After freeing result 8, we‘re using (in bytes): 65948
After query #9, we‘re using (in bytes): 66028
After freeing result 9, we‘re using (in bytes): 66072
After closing the connection, we‘re using (in bytes): 65108
Peak memory usage for the script (in bytes): 88748

我們所做的操作是發(fā)現(xiàn)了執(zhí)行腳本時(shí)出現(xiàn)的一些可疑操作,然后調(diào)整腳本使其給我們提供一些可理解的反饋。我們?cè)俅芜\(yùn)行了腳本,在每次迭代期間使用 memory_get_usage() 查看內(nèi)存使用量的變化。根據(jù)分配的內(nèi)存值的增長情況,暗示了我們用腳本在某個(gè)位置建立了一個(gè)漏洞。由于 mysql_free_result() 函數(shù)不釋放內(nèi)存,因此我們可以認(rèn)為 mysql_query() 并未正確分配內(nèi)存。





回頁首


結(jié)束語

PHP V5.2 版包括一些優(yōu)秀的新工具,可以幫助您更好地洞察腳本的系統(tǒng)內(nèi)存分配情況,以及重新全面控制內(nèi)存管理的精確調(diào)整。當(dāng)?shù)玫接行褂脮r(shí),新內(nèi)存管理工具將支持您的調(diào)試工作,從而重新獲得一些系統(tǒng)資源。



參考資料

學(xué)習(xí)

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
九個(gè)PHP很有用的功能
php獲取當(dāng)前內(nèi)存占用的方法
如何獲知PHP程序占用多少內(nèi)存(memory
一個(gè)PHP數(shù)組應(yīng)該有多大的分析
深入解析PHP內(nèi)存管理之誰動(dòng)了我的內(nèi)存
PHP中的垃圾回收相關(guān)函數(shù)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服