เกี่ยวกับการรั่วไหลของหน่วยความจำ
webman เป็นเฟรมเวิร์กที่ทำงานในหน่วยความจำที่ทำให้เรา ต้องให้ความสนใจกับสถานการณ์การรั่วไหลของหน่วยความจำสักเล็กน้อย อย่างไรก็ตามนักพัฒนาที่ทำงานกับเฟรมเวิร์กนี้ไม่ต้องกังวลมากเกินไป เนื่องจากการรั่วไหลของหน่วยความจำเกิดขึ้นภายใต้เงื่อนไขที่รุนแรงมาก และสามารถหลีกเลี่ยงได้ง่าย ประสบการณ์ในการพัฒนา webman จะมีความคล้ายคลึงกับการพัฒนาจากเฟรมเวิร์กแบบดั้งเดิม ไม่จำเป็นต้องทำการจัดการหน่วยความจำเพิ่มเติม
提示
โปรแกรม monitor ที่มาพร้อมกับ webman จะติดตามการใช้หน่วยความจำของกระบวนการทั้งหมด หากหน่วยความจำที่ใช้ถึงค่าที่กำหนดในmemory_limit
ในไฟล์ php.ini โปรแกรมจะทำการรีสตาร์ทกระบวนการนั้นๆ โดยอัตโนมัติอย่างปลอดภัย เพื่อทำการปล่อยหน่วยความจำ ซึ่งจะไม่มีผลกระทบต่อธุรกิจในระหว่างนั้น
การกำหนดการรั่วไหลของหน่วยความจำ
เมื่อจำนวนคำขอเพิ่มขึ้นอย่างต่อเนื่อง หน่วยความจำที่ใช้โดย webman ก็จะ เพิ่มขึ้นอย่างไม่จำกัด (หมายถึง เพิ่มขึ้นอย่างไม่จำกัด) อาจสูงถึงหลายร้อย MB หรือมากกว่านั้น ซึ่งแบบนี้ถือเป็นการรั่วไหลของหน่วยความจำ
หากหน่วยความจำมีการเพิ่มขึ้น แต่ไม่มีการเพิ่มขึ้นอีกต่อไป จะไม่ถือว่าเป็นการรั่วไหลของหน่วยความจำ
โดยทั่วไปแล้วการใช้หน่วยความจำหลายสิบ MB ถือเป็นเรื่องปกติ เมื่อกระบวนการจัดการกับคำขอที่มีขนาดใหญ่หรือดูแลการเชื่อมต่อจำนวนมาก หน่วยความจำที่ใช้โดยกระบวนการแต่ละตัวอาจสูงถึงหลายร้อย MB ก็เป็นเรื่องที่พบบ่อย หน่วยความจำที่ใช้ส่วนนี้อาจไม่ถูกส่งคืนให้กับระบบปฏิบัติการทั้งหมด เนื่องจากอาจถูกเก็บไว้เพื่อการใช้งานซ้ำ ดังนั้นอาจพบว่าหลังจากการจัดการกับคำขอขนาดใหญ่ หน่วยความจำจะเพิ่มขึ้นโดยไม่ถูกปล่อยคืน ซึ่งถือเป็นปรากฏการณ์ปกติ (สามารถเรียกใช้ gc_mem_caches() เพื่อปล่อยหน่วยความจำที่ว่างบางส่วน)
การรั่วไหลของหน่วยความจำเกิดขึ้นได้อย่างไร
การรั่วไหลของหน่วยความจำจะเกิดขึ้นภายใต้เงื่อนไขสองประการต่อไปนี้:
- มีอาร์เรย์ที่มี อายุยืนยาว (หมายถึงอาร์เรย์ที่มีอายุยืนยาว อาร์เรย์ทั่วไปไม่มีปัญหา)
- และอาร์เรย์ที่มี อายุยืนยาว นี้จะขยายตัวอย่างไม่จำกัด (ธุรกิจจะใส่ข้อมูลเข้าไปเรื่อย ๆ โดยไม่เคลียร์ข้อมูล)
หากเงื่อนไข 1 และ 2 ได้ถูกต้องพร้อมกัน (หมายถึงต้องได้ถูกต้องพร้อมกัน) ก็จะเกิดการรั่วไหลของหน่วยความจำ ถ้าไม่ได้ตามเงื่อนไขดังกล่าวหรือเพียงแค่ตรงตามเงื่อนไขใดเงื่อนไขหนึ่ง จะไม่ถือว่ามีการรั่วไหลของหน่วยความจำ
อาร์เรย์ที่มีอายุยืนยาว
ใน webman อาร์เรย์ที่มีอายุยืนยาวรวมถึง:
- อาร์เรย์ที่ใช้คำสำคัญ static
- อาร์เรย์ที่เป็นคุณสมบัติของ singleton
- อาร์เรย์ที่ใช้คำสำคัญ global
注意
webman อนุญาตให้ใช้ข้อมูลที่มีอายุยืนยาว แต่ต้องมั่นใจว่าข้อมูลในนั้นมีจำนวนที่จำกัด ไม่สามารถขยายเพิ่มขึ้นอย่างไม่จำกัด
ต่อไปนี้เป็นการยกตัวอย่างเพื่ออธิบาย
อาร์เรย์ static ที่ขยายตัวอย่างไม่จำกัด
class Foo
{
public static $data = [];
public function index(Request $request)
{
self::$data[] = time();
return response('hello');
}
}
อาร์เรย์ $data
ที่กำหนดโดยใช้คำสำคัญ static
เป็นอาร์เรย์ที่มีอายุยืนยาว และในตัวอย่าง $data
จะขยายตัวขึ้นเรื่อยๆ ตามจำนวนคำขอที่เข้ามา ส่งผลต่อการรั่วไหลของหน่วยความจำ
อาร์เรย์คุณสมบัติ singleton ที่ขยายตัวอย่างไม่จำกัด
class Cache
{
protected static $instance;
public $data = [];
public function instance()
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
public function set($key, $value)
{
$this->data[$key] = $value;
}
}
รหัสที่เรียกใช้
class Foo
{
public function index(Request $request)
{
Cache::instance()->set(time(), time());
return response('hello');
}
}
Cache::instance()
คืนค่า Cache singleton ซึ่งเป็นอินสแตนซ์ของคลาสที่มีอายุยืนยาว ถึงแม้ว่า $data
ของมันจะไม่ได้ใช้คำสำคัญ static
แต่เนื่องจากคลาสนี้มีอายุยืนยาว ดังนั้น $data
ก็ถือเป็นอาร์เรย์ที่มีอายุยืนยาวเช่นกัน โดยการเพิ่มข้อมูลในอาร์เรย์ $data
ที่มีคีย์ที่แตกต่างกันเรื่อยๆ ทำให้โปรแกรมใช้หน่วยความจำมากขึ้นส่งผลให้เกิดการรั่วไหลของหน่วยความจำ
注意
หากCache::instance()->set(key, value)
เพิ่มคีย์ที่มีจำนวนจำกัด จะไม่มีการรั่วไหลของหน่วยความจำ เนื่องจากอาร์เรย์$data
ไม่ได้ขยายเพิ่มขึ้นอย่างไม่จำกัด
อาร์เรย์ global ที่ขยายตัวอย่างไม่จำกัด
class Index
{
public function index(Request $request)
{
global $data;
$data[] = time();
return response($foo->sayHello());
}
}
อาร์เรย์ที่กำหนดโดยใช้คำสำคัญ global จะไม่ถูกเก็บคืนเมื่อฟังก์ชันหรือเมธอดของคลาสเสร็จสิ้น ดังนั้นมันจึงถือเป็นอาร์เรย์ที่มีอายุยืนยาว โค้ดด้านบนจะเกิดการรั่วไหลของหน่วยความจำเมื่อจำนวนคำขอเพิ่มขึ้นอย่างต่อเนื่อง เช่นเดียวกันอาร์เรย์ที่กำหนดในฟังก์ชันหรือเมธอดโดยใช้คำสำคัญ static ก็ถือเป็นอาร์เรย์ที่มีอายุยืนยาว หากมันขยายตัวอย่างไม่จำกัดก็จะนำไปสู่การรั่วไหลของหน่วยความจำ เช่นเดียวกับ:
class Index
{
public function index(Request $request)
{
static $data = [];
$data[] = time();
return response($foo->sayHello());
}
}
คำแนะนำ
แนะนำให้นักพัฒนาไม่ต้องกังวลเกี่ยวกับการรั่วไหลของหน่วยความจำมากเกินไป เพราะมันเกิดขึ้นน้อยมาก หากเกิดขึ้นอย่างโชคร้าย เราสามารถใช้การทดสอบแรงกดดันเพื่อตรวจหาว่าส่วนใดของโค้ดก่อให้เกิดการรั่วไหล เพื่อระบุปัญหา แม้ว่า นักพัฒนาจะไม่สามารถหาจุดรั่วไหลได้ แต่บริการ monitor ที่มาพร้อมกับ webman จะรีสตาร์ทกระบวนการที่มีการรั่วไหลของหน่วยความจำอย่างปลอดภัยในเวลาที่เหมาะสม เพื่อปล่อยหน่วยความจำ
หากท่านต้องการหลีกเลี่ยงการรั่วไหลของหน่วยความจำอย่างเต็มที่ สามารถอ้างอิงตามคำแนะนำด้านล่างนี้
- พยายามหลีกเลี่ยงการใช้การกำหนดค่าอาร์เรย์ด้วยคำสำคัญ
global
และstatic
หากจำเป็นต้องใช้ ให้แน่ใจว่าอาร์เรย์นั้นไม่สามารถขยายตัวได้เรื่อย ๆ - สำหรับคลาสที่ไม่คุ้นเคย ควรหลีกเลี่ยงการใช้ singleton และให้ใช้คำสั่ง new ในการสร้างอ็อบเจ็กต์ หากต้องการใช้ singleton ควรตรวจสอบว่ามีคุณสมบัติที่เป็นอาร์เรย์ที่ขยายตัวอย่างไม่จำกัดหรือไม่