4

I'm trying to debug a memory leak in my application, and I think I managed to reduce it to this minimal example:

from typing import Deque
import gc
import os
import psutil
from concurrent.futures import ThreadPoolExecutor

process = psutil.Process(os.getpid())  # we'll use this to track memory usage
executor = ThreadPoolExecutor()  # generic executor 
n = 100  # number of tasks to run concurrently at any time
prev = 0  # previous maximum memory usage
m = 10_000


def do():  # an arbitrary function that returns a large value
    return list(range(m))

# initialize a deque that can track all our running futures
futures = Deque(executor.submit(do) for _ in range(n))

i = 0  # future counter
while futures:
    f = futures.popleft()  # pop one of the futures (removing its reference from the deque)
    result = f.result()  
    del result, f  # delete the future (the future is definitely removed now)
    # check the memory usage and print a message if it is a new record
    new_mem = process.memory_info().rss
    if new_mem > prev:
        print(f"{i}: {new_mem:,} bytes, {len(futures)} tasks pending")
        prev = new_mem
    # enqueue a new task
    futures.append(executor.submit(do))
    gc.collect()
    i+=1

Essentially what we do here is keep a rotating queue of tasks that return a large value, ensuring that there are no more than n tasks running concurrently at any time.

We would expect, after about max_workers tasks have completed, that top memory usage would reach a plateau since none of the data from the futures is being preserved.

However, on python 3.7.12, we see that memory usage increases continually and plateaus sometimes even on the thousandth task!

This outcome is preserved even when we change do() to return a numpy array, when we limit the max_workers to a smaller number, and when we reduce n.

EDIT: I added a table measuring the pear memory usage (on my machine) of a process running this code by iteration count, for different values of m

| peak memory usage after N iterations | m=1,000    | m=5,000    | m=10,000   |
|--------------------------------------|------------|------------|------------|
| 500                                  | 16,961,536 | 37,662,720 | 61,689,856 |
| 1,000                                | 17,408,000 | 38,981,632 | 62,132,224 |
| 1,500                                | 17,760,256 | 39,374,848 | 62,164,992 |
| 2,000                                | 18,063,360 | 40,177,664 | 62,832,640 |
| 2,500                                | 18,219,008 | 40,845,312 | 62,832,640 |
| 3,000                                | 18,374,656 | 40,931,328 | 63,156,224 |
| 3,500                                | 18,493,440 | 41,492,480 | 63,328,256 |
| 4,000                                | 18,604,032 | 41,586,688 | 63,328,256 |
| 4,500                                | 18,673,664 | 41,586,688 | 63,328,256 |
| 5,000                                | 18,763,776 | 41,586,688 | 63,328,256 |
| 5,500                                | 18,800,640 | 41,586,688 | 63,328,256 |
| 6,000                                | 18,853,888 | 41,615,360 | 63,328,256 |
| 6,500                                | 18,898,944 | 41,660,416 | 63,328,256 |
| 7,000                                | 18,931,712 | 41,795,584 | 63,328,256 |
| 7,500                                | 18,952,192 | 41,930,752 | 63,328,256 |
| 8,000                                | 18,952,192 | 42,061,824 | 63,328,256 |
| 8,500                                | 18,993,152 | 42,377,216 | 63,361,024 |
| 9,000                                | 19,046,400 | 42,463,232 | 63,528,960 |
| 9,500                                | 19,075,072 | 42,463,232 | 63,528,960 |
| 10,000                               | 19,075,072 | 42,463,232 | 63,528,960 |
| 10,500                               | 19,083,264 | 42,463,232 | 63,533,056 |
| 11,000                               | 19,083,264 | 42,463,232 | 63,664,128 |
| 11,500                               | 19,128,320 | 42,553,344 | 63,664,128 |
| 12,000                               | 19,185,664 | 42,553,344 | 63,664,128 |
| 12,500                               | 19,185,664 | 42,553,344 | 63,664,128 |
| 13,000                               | 19,185,664 | 42,553,344 | 63,664,128 |
| 13,500                               | 19,193,856 | 42,553,344 | 64,167,936 |
| 14,000                               | 19,193,856 | 42,594,304 | 64,167,936 |
| 14,500                               | 19,193,856 | 42,594,304 | 64,167,936 |
| 15,000                               | 19,202,048 | 42,594,304 | 64,249,856 |
| 15,500                               | 19,202,048 | 42,594,304 | 64,249,856 |
| 16,000                               | 19,222,528 | 42,594,304 | 64,462,848 |
| 16,500                               | 19,353,600 | 42,594,304 | 64,499,712 |
| 17,000                               | 19,361,792 | 42,635,264 | 64,499,712 |
| 17,500                               | 19,415,040 | 42,725,376 | 64,499,712 |
| 18,000                               | 19,423,232 | 42,766,336 | 64,499,712 |
| 18,500                               | 19,431,424 | 42,811,392 | 64,499,712 |
| 19,000                               | 19,476,480 | 42,811,392 | 64,499,712 |
| 19,500                               | 19,537,920 | 42,811,392 | 64,520,192 |
| 20,000                               | 19,607,552 | 42,856,448 | 65,044,480 |
| 20,500                               | 19,607,552 | 42,946,560 | 65,044,480 |
| 21,000                               | 19,636,224 | 43,110,400 | 65,044,480 |
| 21,500                               | 19,644,416 | 43,110,400 | 65,044,480 |
| 22,000                               | 19,652,608 | 43,110,400 | 65,044,480 |
| 22,500                               | 19,722,240 | 43,110,400 | 65,044,480 |
| 23,000                               | 19,746,816 | 43,110,400 | 65,044,480 |
| 23,500                               | 19,746,816 | 43,110,400 | 65,044,480 |
| 24,000                               | 19,746,816 | 43,110,400 | 65,044,480 |
| 24,500                               | 19,775,488 | 43,110,400 | 65,044,480 |
| 25,000                               | 19,800,064 | 43,110,400 | 65,044,480 |
| 25,500                               | 19,820,544 | 43,110,400 | 65,044,480 |
| 26,000                               | 19,886,080 | 43,110,400 | 65,044,480 |
| 26,500                               | 19,886,080 | 43,118,592 | 65,044,480 |
| 27,000                               | 19,894,272 | 43,118,592 | 65,044,480 |
| 27,500                               | 19,939,328 | 43,208,704 | 65,044,480 |
| 28,000                               | 19,947,520 | 43,208,704 | 65,044,480 |
| 28,500                               | 20,058,112 | 43,208,704 | 65,044,480 |
| 29,000                               | 20,086,784 | 43,208,704 | 65,044,480 |
| 29,500                               | 20,086,784 | 43,208,704 | 65,044,480 |
| 30,000                               | 20,086,784 | 43,208,704 | 65,044,480 |
bentheiii
  • 451
  • 3
  • 15
  • Have you ever solved this problem? If I remeber correctly I had this issue with multiprocessing, now im trying to find solution with ProcessPoolExecutor, memory just keeps growing with each process – Grzegorz Krug Jul 25 '23 at 19:11

0 Answers0