diff --git a/lib/ngtcp2_acktr.c b/lib/ngtcp2_acktr.c
index 6101f78d616626cfdc17fb3c635f02075b99b455..5796c70fa794a9a8080e4b13f4fdb1a6fef7918c 100644
--- a/lib/ngtcp2_acktr.c
+++ b/lib/ngtcp2_acktr.c
@@ -202,8 +202,18 @@ ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
   ngtcp2_acktr_ack_entry *ent;
 
   if (unprotected) {
+    if (ngtcp2_ringbuf_full(&acktr->hs_acks)) {
+      ent = ngtcp2_ringbuf_get(&acktr->hs_acks,
+                               ngtcp2_ringbuf_len(&acktr->hs_acks) - 1);
+      ngtcp2_mem_free(acktr->mem, ent->ack);
+    }
     ent = ngtcp2_ringbuf_push_front(&acktr->hs_acks);
   } else {
+    if (ngtcp2_ringbuf_full(&acktr->acks)) {
+      ent = ngtcp2_ringbuf_get(&acktr->acks,
+                               ngtcp2_ringbuf_len(&acktr->acks) - 1);
+      ngtcp2_mem_free(acktr->mem, ent->ack);
+    }
     ent = ngtcp2_ringbuf_push_front(&acktr->acks);
   }
   ent->ack = fr;
diff --git a/lib/ngtcp2_ringbuf.c b/lib/ngtcp2_ringbuf.c
index a5754dba95eac8ea2fc77df16ddf751d1465d84b..a017607013cf4216b094e970a94d35759b3867e6 100644
--- a/lib/ngtcp2_ringbuf.c
+++ b/lib/ngtcp2_ringbuf.c
@@ -78,3 +78,5 @@ void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset) {
 }
 
 size_t ngtcp2_ringbuf_len(ngtcp2_ringbuf *rb) { return rb->len; }
+
+int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->nmemb; }
diff --git a/lib/ngtcp2_ringbuf.h b/lib/ngtcp2_ringbuf.h
index 260c5a826632d944bd23185262cfccb0856f44e4..2ba4a2046516cec4cc8ca83023f2dad62dc0ac3b 100644
--- a/lib/ngtcp2_ringbuf.h
+++ b/lib/ngtcp2_ringbuf.h
@@ -91,4 +91,7 @@ void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset);
 /* ngtcp2_ringbuf_len returns the number of elements stored. */
 size_t ngtcp2_ringbuf_len(ngtcp2_ringbuf *rb);
 
+/* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
+int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb);
+
 #endif /* NGTCP2_RINGBUF_H */