--- a/src/Dispatcher.h
+++ b/src/Dispatcher.h
@@ -85,6 +85,7 @@
 class PacketManager {
 public:
+  virtual ~PacketManager() { }
   virtual Packet* allocNew() = 0;
   virtual void free(Packet* packet) = 0;
 
--- a/src/helpers/StaticPoolPacketManager.h
+++ b/src/helpers/StaticPoolPacketManager.h
@@ -4,6 +4,7 @@
 
 class PacketQueue {
   mesh::Packet** _table;
   uint8_t* _pri_table;
   uint32_t* _schedule_table;
   int _size, _num;
 
 public:
   PacketQueue(int max_entries);
+  ~PacketQueue();
   mesh::Packet* get(uint32_t now);
   bool add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for);
   int count() const { return _num; }
@@ -21,6 +22,7 @@
 class StaticPoolPacketManager : public mesh::PacketManager {
   PacketQueue unused, send_queue, rx_queue;
 
 public:
   StaticPoolPacketManager(int pool_size);
+  ~StaticPoolPacketManager() override;
 
   mesh::Packet* allocNew() override;
--- a/src/helpers/StaticPoolPacketManager.cpp
+++ b/src/helpers/StaticPoolPacketManager.cpp
@@ -3,6 +3,13 @@
 PacketQueue::PacketQueue(int max_entries) {
   _table = new mesh::Packet*[max_entries];
   _pri_table = new uint8_t[max_entries];
   _schedule_table = new uint32_t[max_entries];
   _size = max_entries;
   _num = 0;
 }
 
+PacketQueue::~PacketQueue() {
+  delete[] _table;
+  delete[] _pri_table;
+  delete[] _schedule_table;
+}
+
 int PacketQueue::countBefore(uint32_t now) const {
@@ -71,6 +78,15 @@
 StaticPoolPacketManager::StaticPoolPacketManager(int pool_size): unused(pool_size), send_queue(pool_size), rx_queue(pool_size) {
   // load up our unusued Packet pool
   for (int i = 0; i < pool_size; i++) {
     unused.add(new mesh::Packet(), 0, 0);
   }
 }
 
+StaticPoolPacketManager::~StaticPoolPacketManager() {
+  // Free all Packet objects from all three queues
+  mesh::Packet* p;
+  while ((p = unused.removeByIdx(0)) != NULL) delete p;
+  while ((p = send_queue.removeByIdx(0)) != NULL) delete p;
+  while ((p = rx_queue.removeByIdx(0)) != NULL) delete p;
+  // PacketQueue destructors handle their own array cleanup
+}
+
 mesh::Packet* StaticPoolPacketManager::allocNew() {
