CAT LoRa Starter Kit ตอนที่ 13 ตรวจสอบหน่วยความจำ (RAM) ที่ใช้ไปเพื่อป้องกันโปรแกรมพัง

Choonewza
2 min readJan 26, 2020

ในบทความนี้จะเป็นการกล่าวถึงวิธีการตรวจสอบหน่วยความจำ (RAM) ที่เหลืออยู่ของบอร์ด เพื่อป้องกันการใช้พื้นที่หน่วยความจำจนเต็มแล้วทำให้โปรแกรมพัง โดยปกติแล้วในการประกาศตัวแปรทุกครั้ง จะมีการจองหน่วยความจำส่วนหนึ่งไว้เพื่อจัดเก็บค่าของตัวแปรนั้นๆ โดยที่พื้นที่ๆ จอง จะมีขนาดตามชนิดของตัวแปรที่จะจัดเก็บ เรามาเขียนโปรแกรมเพื่อหาขนาดของ data type แต่ละชนิดกัน

ทำไมเราต้องสนใจขนาดของข้อมูลที่จะถูกจองใน RAM พวกนี้ด้วยละ ก็เพราะว่าการพัฒนาโปรแกรมบนไมโครคอนโทรลเลอร์ มักจะให้ RAM มาไม่เยอะ ยิ่งโปรแกรมมีความซับซ้อนและขนาดใหญ่ขึ้น ก็จะมีตัวแปรที่ใช้เยอะขึ้นเป็นเท่าตัว ทำให้มีการจองใช้พื้นที่ RAM ในปริมาณที่สูง

แต่นั้นไม่ใช่ปัญหาที่เราต้องสนใจครับ เพราะการที่เราประกาศตัวแปรใน Function scope ใด เมื่อจบการทำงานใน Function scope นั้น หน่วยความจำที่ตัวแปรใช้ไปจะถูกเรียกคืนโดยอัตโนมัติ ทำให้ RAM แทบจะไม่มีวันเต็มเลย

void setup(){ ... }void loop(){
double a = 5.0;
double b = 4.0;
double c = a / b;
Serial.println(c);
}

จากตัวอย่าง มีการประการตัวแปร a , b และ c ดังนั้นเริ่มต้นมันจะทำการจองพื้นที่ไว้ใช้เก็บค่าตัวแปรทั้งสามตัวนั้น แต่เมื่อฟังก์ชั่น loop() สิ้นสุด ตัวแปรทั้งสามก็จะคืนพื้นที่ที่ได้จองไว้เป็นแบบนี้ไปเรื่อยๆ ไม่ว่าจะวนมากี่รอบก็ตาม จึงไม่มีทางที่ RAM จะเต็ม

double c = 0;void setup(){ ... }void loop(){
double a = 5.0;
double b = 4.0;
c = a / b;
Serial.println(c);
}

จากตัวอย่าง ตัวแปร c ถูกประกาศอยู่นอกฟังก์ชั่น loop() ดังนั้นตัวแปร c จะถือครองหน่วยความจำขนาด 8 Byte ตลอดไป ในขนาดเท่าเดิม ไม่ว่าจะวนลูปกี่รอบก็ตาม จึงไม่ใช่ปัญหา

แต่สิ่งที่เป็นปัญหาจริง ๆ ของเรา คือ ในภาษา C และ C++ มีสิ่งที่เรียกว่า Pointer

Pointer คืออะไร​ ? : http://marcuscode.com/lang/cpp/pointers

ตัวแปรแบบ Pointer มันมีปัญหายังไงละ ?

ก็เพราะตัวแปร Pointer เมื่อเราไม่ใช้งานมันแล้วหรือเมื่อจบ Function scope แล้ว ตัวแปรตัวนี้จะไม่คืนหน่วยความจำที่มันใช้งานอยู่ ดังนั้นถ้ามีการวนลูปไปเรื่อยๆ จะเกิดการสร้างตัวแปรทับกันไป จนกว่า RAM หมด มีผลทำให้โปรแกรมค้าง และบอร์ดแฮ็งค์

MemoryFree Library : https://github.com/mpflaga/Arduino-MemoryFree

ตัวแปร msg ถูกประกาศเป็นแบบ Pointer ทำให้เมื่อมีการวนลูปเกิดขึ้น ทันทีที่เข้าฟังก์ชั่น new String(“55555”) ตัวใหม่จะถูกสร้างขึ้น แต่ new String(“55555”) ตัวเก่าไม่ได้ถูกทำลายไป จะยังคงถือครองหน่วยความจำที่ใช้ไปไว้อยู่ มีผลทำให้หน่วยความจำของระบบลดลงเรื่อยๆ ไปจนหมด

RAM ลดลงเรื่อย ๆ
RAM หมด บอร์ดค้าง

ถ้าเราไม่ใส่ delay(1000); ไว้ในโค๊ด มันจะทำให้ RAM หมดภายในเสี้ยววินาที เป็นผลให้เราไม่สามารถอัปโหลดโค๊ดใหม่เข้าบอร์ดได้ แก้ได้โดยกดปุ่ม Reset ที่บอร์ดติดกัน 2 ครั้ง จะเป็นการลบโปรแกรมออกทั้งหมดทันที

วิธีแก้ปัญหา

ทำได้โดยเมื่อไม่ใช้งานตัวแปร Pointer เราต้องลบออกเองทุกครั้งโดยใช้คำสั่ง delete <ชื่อตัวแปร>

void loop() {
String *msg = new String("55555");
delete msg;
showFreeMemory();
}
ผลลัพธ์เมื่อใส่ delete msg

จะเห็นว่าการถือครองหน่วยความจำจะไม่เกิดขึ้น RAM ไม่มีการลดลง

Attribute Pointer in Class

ในบทความชุดนี้ของผมจะเน้นไปที่การเขียนโปรแกรมแบบ OOP ทำให้มีการสร้าง Class Library ขึ้น และหลายอันมีการใช้งานตัวแปร Attribute ที่เป็นแบบ Pointer ด้วย ซึ่งจะทำมีปัญหาได้ ดังนั้นเราต้องทำการลบ Pointer Attribute ออกทุกครั้งเมื่อไม่มีการใช้ object ที่สร้างจาก Class Library นี้แล้ว โดยเราจะไปลบที่ Destructor ของ Class ที่เราสร้าง ดังนี้

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

--

--