0147 | PHP Fatal error: Out of memory

Tuesday, February 5th, 2013 Posted in Linux, PHP Coding, Web Server | No Comments »

Fatal error: Out of memory (allocated 4194304) (tried to allocate 14156 bytes) in /var/www/html/script.php on line 123

เชื่อว่าคนทำเว็บที่ใช้ PHP หลายๆ คนคงเคยเจอปัญหานี้มาไม่มากก็น้อยกันอยู่ หลายๆ คนเห็น error อันนี้แล้วก็ไปเข้าใจผิดว่า server แรมหมดอะไรงี้ด้วย เดี๋ยวจะมาอธิบายให้ครับ

  • Error นี้ไม่ได้เกี่ยวห่าอะไรเลยกับ RAM ของ server หมดครับ การ reboot เครื่องหรือ upgrade spec ของ VPS ของท่านไม่ได้ช่วยให้อาการนี้หายแต่อย่างใด
  • มันคือ Error ที่มาจากระบบจัดการการใช้ Memory ของ PHP เอง (ตั้งใน php.ini ชื่อ option ว่า memory_limit)
  • มันกำลังบอกว่า เจ้าของ server ตั้งจำกัดการใช้งาน Memory ของ PHP ไว้ (allocated ***) bytes
  • และมันบอกว่า script ใช้จนเต็ม limit ไปแล้ว แต่จะขอใช้เพิ่มอีก (tried to allocate *** bytes)
  • พอใช้เกิน limit ของที่ตั้งไว้ใน php.ini PHP ก็เลยสั่งตัดการทำงาน พร้อมกับพ่น error นั่นออกมา

ความจริง option นี้มีประโยชน์มากสำหรับ shared hosting เพื่อป้องกันไม่ให้มี script ใดๆ สามารถใช้งานแรมจนหมดได้… (อาจจะเกิดจากเขียน code ผิด หรืออะไรก็แล้วแต่) แต่การตั้งค่านี้ต่ำไปก็มีผลกระทบกับ CMS ที่เขียนมาไม่ดี และมีการใช้ทรัพยากรหนักๆ ครับ (WordPress / Joomla เป็นต้น)

ค่า memory_limit ของ PHP เนี่ย เท่าที่ใช้งานมาไม่ควรตั้งต่ำกว่า 8M (8388608) ครับ และสำหรับการใช้งาน CMS อย่าง wordpress หรือ joomla ที่ call stack ไม่รู้จะยาวไปหาอะไร แนะนำให้ตั้งที่ไม่ต่ำกว่า 64M (67108864) ครับ

Tags: ,

0010 | MySQL Memory Engine

Saturday, May 10th, 2008 Posted in Database | 2 Comments »

ก่อนอื่นขอรายงานสถานการณ์+บ่นซะก่อน แง่มๆ
วันที่ 7 ตอน 22.00 น. ไฟฟ้าใช้ได้ตามปกติแล้วครับ
แล้วก็… aircard กลับมาใช้ได้ตามปกติแล้ว เย้ๆๆ
เซ็งแทบตาย ต้องไปจิ้มสายเน็ตเพื่อนใช้อยู่ แล้วมันเร็ว
เอ้ย แล้วมันต้องเกรงใจอะ น่าเบื่อที่สุด ทำอะไรไม่สะใจเลย

กลับเข้าเรื่องกันดีกว่า
วันนี้จะมาว่าด้วย MySQL Memory Engine ครับ

Memory Engine เป็นรูปแบบตารางของ MySQL แบบหนึ่ง
ซึ่งมีโครงสร้างคล้ายๆ กับ MyISAM บ้าง นิดๆ หน่อยๆ
เพียงแต่แทนที่จะเก็บไว้เป็นไฟล์ .MYD ไว้บนเครื่อง ก็เปลี่ยนมาเป็น
เก็บลง shared memory ของ master process แทน
แน่นอนครับ ผลลัพท์ที่ได้มันก็มาจากความเร็วของ RAM ที่ท่านใช้
ว่ามันจะเร็วได้แค่ไหน ซึ่งปกติ ประสิทธิภาพความเร็วที่ทำได้จะอยู่ราวๆ 50-150 เท่าของ MyISAM ครับ

อ๊ะๆ เห็นมันเร็วกันบ้าพลังขนาดนี้นี่ อย่ามาคิดเชียวว่าทำไมไม่เก็บไว้ใน Memory ให้หมด
สาเหตุมันก็เพราะปัจจัยตามนี้ครับ

  1. เครื่องมีแรมเท่าไหร่ มันก็เก็บได้ไม่เกิน 1/2 ของแรมนั่นแหละครับ
  2. ใช้ field ประเภท text/blob ทุกชนิดไม่ได้ (ใช้ varchar ได้อยู่นะครับ)
  3. restart mysql ปุ๊ป ข้อมูลหายเรียบ (ก็มันเก็บในแรมนี่)
  4. เปลืองพื้นที่มากกว่า MyISAM เยอะ (ตาราง MyISAM ขนาด 10 MB เวลาแปลงเป็น Memory จะใช้แรมประมาณ 40 MB)
  5. ต้อง allocate memory เป็น block แต่ละ block ขนาดประมาณ 4-8 MB (เอาเป็นว่าหารเลขฐานสองลงตัวอะ)

ว่าแต่ร่ายซะเสียเลยแฮะเรา (ฮาๆ)
เอาเป็นว่า เนื่องด้วยเหตุผลข้อ 3 ทำให้เราไม่สามารถเก็บข้อมูลลงใน Memory Engine ได้ถาวรแน่นอนครับ
ดังนั้น ตารางแบบนี้เหมาะสำหรับเก็บค่า “ชั่วคราว” มากกว่า
เช่นพวกสถิติ user online, session ของเว็บไซต์ อะไรพวกนี้
ซึ่งวิธีแปลงก็ง่ายๆ ครับ

ALTER TABLE table ENGINE=Memory;

แค่นี้เอง สั้นๆ ง่ายๆ ได้ใจความ
รูปแบบการใช้งานที่เหมาะสม (และผมใช้อยู่ปัจจุบัน)คือ ตาราง peers ของเว็บ bittorrent ครับ
reset ไปมันก็เข้าใหม่ได้ ไม่มีปัญหาอะไรมาก แถมตารางนี้ access หนักมาก ถี่ยิบๆ
ก็เลยเหมาะต่อการใช้ Memory Engine ที่สุดเลย

รองลงมาก็คือ download session ของเว็บฝากไฟล์
พวกนี้ปล่อยๆ มันได้ครับ ใช้ไม่่ค่อยเยอะหรอก

ทีนี้ ปัญหาที่จะเจอคือ Error ต่อไปนี้

The table ‘table‘ is full

ทั้งนี้เนื่องมาจาก MySQL มีการกำหนดขนาดสูงสุดของตารางประเภท Memory ไว้ครับ
ว่า 1 ตารางสามารถจุข้อมูลได้ทั้งหมดกี่ MB ใน variable ที่ชื่อ max_heap_table_size ครับ
โดยค่าปกติของ MySQL 5.0 คือ 16 MB
อยากให้มันใหญ่ได้เท่าไหร่ก็ใส่ไปโลด /etc/my.cnf ในส่วนของ mysqld สั้นๆ ง่ายๆ ครับ

จบและ คราวหน้าถ้าไม่ลืมจะมาพูดถึง MySQL Indexes ครับ

Tags: , ,