Repository: getsentry/sentry-python

Issue:
Abnormal memory consumption in celery integration
### How do you use Sentry?

Sentry Saas (sentry.io)

### Version

1.16.0-1.18.0

### Steps to Reproduce

So I have created celery application with sentry integration and worker that allocates large chunks of memory.
I observe that when I use `sentry-sdk==1.15.0` my worker allocates memory ones and stays roughly at the same level for each consecutive task, whereas with version  `>1.15.0` (`1.16.0`, `1.17.0`, `1.18.0`) memory consumption increases with each task. 


### Expected Result

I expect that with newer version of `sentry-sdk` will behave like `1.15.0` in my case.

### Actual Result

I've prepared repository with a code that could help to reproduce a bug.
https://github.com/oleks-popovych/sentry-leak


Discussion:
Hey @oleks-popovych 

Thanks for reporting this and supplying a demo repo for reproduction! 

I put it on my list and will have a look.
No updates yet. Hope to have time soon
I have now tried to reproduce a memory leak in Celery (for some internal stuff) and maybe this is related: https://github.com/getsentry/sentry-python/issues/2034

thx for the great repro @oleks-popovych!

so this one I'm pretty sure is about the profiler, I tried with the latest `1.21.0`
cc @Zylphrex 

### without `profiles_sample_rate`
```
[2023-04-26 15:07:22,425: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1895360.0 Mb
[2023-04-26 15:07:24,213: INFO/ForkPoolWorker-1] Task person[8ced368d-a332-4a63-931e-e1eff617dc58] succeeded in 1.7875764629970945s: None
[2023-04-26 15:07:24,217: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1899876.0 Mb
[2023-04-26 15:07:26,000: INFO/ForkPoolWorker-1] Task person[bb07f696-13ff-43fa-9275-86150486c4a1] succeeded in 1.783820864999143s: None
[2023-04-26 15:07:26,006: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1900120.0 Mb
[2023-04-26 15:07:27,876: INFO/ForkPoolWorker-1] Task person[4f920181-c3d8-4a15-86f5-35a2fdc845c5] succeeded in 1.869866226999875s: None
[2023-04-26 15:07:27,881: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1900248.0 Mb
[2023-04-26 15:07:29,709: INFO/ForkPoolWorker-1] Task person[427a6087-9f40-4edf-b1b2-f7862a5398ac] succeeded in 1.82814419299757s: None
```

### with `profiles_sample_rate=1.0`

```
[2023-04-26 15:05:19,029: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1896428.0 Mb
[2023-04-26 15:05:20,990: INFO/ForkPoolWorker-1] Task person[89266c17-6bc7-40cf-9b41-030a4e4cfa76] succeeded in 1.9605774160008878s: None
[2023-04-26 15:05:20,995: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 2651540.0 Mb
[2023-04-26 15:05:23,061: INFO/ForkPoolWorker-1] Task person[1b8b8afe-ebb2-4fb6-a9cd-b74794479a39] succeeded in 2.0662039470007585s: None
[2023-04-26 15:05:23,067: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3777180.0 Mb
[2023-04-26 15:05:25,400: INFO/ForkPoolWorker-1] Task person[cf442401-94e2-43f8-bba1-29773a655679] succeeded in 2.3336790859975736s: None
[2023-04-26 15:05:25,405: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 5652644.0 Mb
[2023-04-26 15:05:27,678: INFO/ForkPoolWorker-1] Task person[7413d977-7fd5-4e3e-9db7-2290b4dfdc4b] succeeded in 2.273330175998126s: None
```

with [`pympler.tracker.SummaryTracker`](https://pythonhosted.org/Pympler/muppy.html#muppy)

<details>

<summary>without profiling</summary>

```
[2023-04-26 15:15:56,207: WARNING/ForkPoolWorker-1]                        types |   # objects |   total size
[2023-04-26 15:15:56,208: WARNING/ForkPoolWorker-1] ============================ | =========== | ============
[2023-04-26 15:15:56,208: WARNING/ForkPoolWorker-1]                          str |       11036 |    838.55 KB
[2023-04-26 15:15:56,209: WARNING/ForkPoolWorker-1]                         list |        9441 |    808.20 KB
[2023-04-26 15:15:56,209: WARNING/ForkPoolWorker-1]                         dict |         744 |    230.98 KB
[2023-04-26 15:15:56,209: WARNING/ForkPoolWorker-1]                         code |         785 |    136.81 KB
[2023-04-26 15:15:56,210: WARNING/ForkPoolWorker-1]                         type |          87 |    100.80 KB
[2023-04-26 15:15:56,211: WARNING/ForkPoolWorker-1]                          int |        2204 |     60.66 KB
[2023-04-26 15:15:56,211: WARNING/ForkPoolWorker-1]                        tuple |         449 |     26.19 KB
[2023-04-26 15:15:56,211: WARNING/ForkPoolWorker-1]    celery.bootsteps.StepType |          16 |     17.27 KB
[2023-04-26 15:15:56,211: WARNING/ForkPoolWorker-1]                          set |          40 |     16.94 KB
[2023-04-26 15:15:56,212: WARNING/ForkPoolWorker-1]        weakref.ReferenceType |         192 |     13.50 KB
[2023-04-26 15:15:56,212: WARNING/ForkPoolWorker-1]                         cell |         292 |     11.41 KB
[2023-04-26 15:15:56,213: WARNING/ForkPoolWorker-1]                       method |         142 |      8.88 KB
[2023-04-26 15:15:56,213: WARNING/ForkPoolWorker-1]          function (__init__) |          62 |      8.72 KB
[2023-04-26 15:15:56,213: WARNING/ForkPoolWorker-1]            collections.deque |          10 |      6.09 KB
[2023-04-26 15:15:56,214: WARNING/ForkPoolWorker-1]   builtin_function_or_method |          78 |      5.48 KB
[2023-04-26 15:15:56,215: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 67260.0 Mb
[2023-04-26 15:15:58,727: INFO/ForkPoolWorker-1] Task person[fce4efb5-2e16-48fd-818d-0d005b6ba8bb] succeeded in 3.5504630110008293s: None
[2023-04-26 15:15:59,673: WARNING/ForkPoolWorker-1]                              types |   # objects |   total size
[2023-04-26 15:15:59,673: WARNING/ForkPoolWorker-1] ================================== | =========== | ============
[2023-04-26 15:15:59,674: WARNING/ForkPoolWorker-1]                                str |        1405 |    112.14 KB
[2023-04-26 15:15:59,674: WARNING/ForkPoolWorker-1]                               dict |         294 |    110.83 KB
[2023-04-26 15:15:59,675: WARNING/ForkPoolWorker-1]                               code |         426 |     73.72 KB
[2023-04-26 15:15:59,676: WARNING/ForkPoolWorker-1]                               type |          55 |     61.83 KB
[2023-04-26 15:15:59,676: WARNING/ForkPoolWorker-1]                               list |         505 |     48.64 KB
[2023-04-26 15:15:59,677: WARNING/ForkPoolWorker-1]                                set |          17 |     34.09 KB
[2023-04-26 15:15:59,677: WARNING/ForkPoolWorker-1]                              tuple |         266 |     15.86 KB
[2023-04-26 15:15:59,677: WARNING/ForkPoolWorker-1]                                int |         402 |     11.27 KB
[2023-04-26 15:15:59,678: WARNING/ForkPoolWorker-1]   redis.client.CaseInsensitiveDict |           1 |      9.11 KB
[2023-04-26 15:15:59,678: WARNING/ForkPoolWorker-1]              weakref.ReferenceType |          94 |      6.61 KB
[2023-04-26 15:15:59,679: WARNING/ForkPoolWorker-1]                              bytes |           7 |      3.93 KB
[2023-04-26 15:15:59,679: WARNING/ForkPoolWorker-1]                  collections.deque |           6 |      3.66 KB
[2023-04-26 15:15:59,679: WARNING/ForkPoolWorker-1]         builtin_function_or_method |          49 |      3.45 KB
[2023-04-26 15:15:59,680: WARNING/ForkPoolWorker-1]                function (__init__) |          24 |      3.38 KB
[2023-04-26 15:15:59,680: WARNING/ForkPoolWorker-1]                               cell |          70 |      2.73 KB
[2023-04-26 15:15:59,681: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1958944.0 Mb
[2023-04-26 15:16:01,518: INFO/ForkPoolWorker-1] Task person[3b86a496-f9eb-405f-b927-fe9f81d2e188] succeeded in 2.786324720000266s: None
[2023-04-26 15:16:02,467: WARNING/ForkPoolWorker-1]                            types |   # objects |   total size
[2023-04-26 15:16:02,467: WARNING/ForkPoolWorker-1] ================================ | =========== | ============
[2023-04-26 15:16:02,468: WARNING/ForkPoolWorker-1]                              str |         281 |     20.43 KB
[2023-04-26 15:16:02,468: WARNING/ForkPoolWorker-1]                             list |         256 |     20.00 KB
[2023-04-26 15:16:02,468: WARNING/ForkPoolWorker-1]                             dict |          25 |      5.82 KB
[2023-04-26 15:16:02,469: WARNING/ForkPoolWorker-1]                              int |          90 |      2.48 KB
[2023-04-26 15:16:02,469: WARNING/ForkPoolWorker-1]                            tuple |          19 |      1.10 KB
[2023-04-26 15:16:02,469: WARNING/ForkPoolWorker-1]                            bytes |           0 |    675     B
[2023-04-26 15:16:02,470: WARNING/ForkPoolWorker-1]                       re.Pattern |           2 |    556     B
[2023-04-26 15:16:02,470: WARNING/ForkPoolWorker-1]          sentry_sdk.tracing.Span |           2 |    336     B
[2023-04-26 15:16:02,470: WARNING/ForkPoolWorker-1]                           method |           5 |    320     B
[2023-04-26 15:16:02,471: WARNING/ForkPoolWorker-1]                datetime.datetime |           5 |    240     B
[2023-04-26 15:16:02,471: WARNING/ForkPoolWorker-1]   sentry_sdk.tracing.Transaction |           1 |    232     B
[2023-04-26 15:16:02,471: WARNING/ForkPoolWorker-1]                        frozenset |           1 |    216     B
[2023-04-26 15:16:02,472: WARNING/ForkPoolWorker-1]                 <enum 'Options'> |           4 |    184     B
[2023-04-26 15:16:02,472: WARNING/ForkPoolWorker-1]            weakref.ReferenceType |           2 |    144     B
[2023-04-26 15:16:02,473: WARNING/ForkPoolWorker-1]                   ssl.SSLContext |           1 |    128     B
[2023-04-26 15:16:02,474: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1971652.0 Mb
[2023-04-26 15:16:04,284: INFO/ForkPoolWorker-1] Task person[69610985-9b50-4313-b824-96f1b340cb6b] succeeded in 2.762680328996794s: None
[2023-04-26 15:16:05,238: WARNING/ForkPoolWorker-1]                              types |   # objects |   total size
[2023-04-26 15:16:05,238: WARNING/ForkPoolWorker-1] ================================== | =========== | ============
[2023-04-26 15:16:05,239: WARNING/ForkPoolWorker-1]                         memoryview |           3 |    552     B
[2023-04-26 15:16:05,240: WARNING/ForkPoolWorker-1]                              bytes |           1 |    440     B
[2023-04-26 15:16:05,240: WARNING/ForkPoolWorker-1]         builtin_function_or_method |           2 |    144     B
[2023-04-26 15:16:05,240: WARNING/ForkPoolWorker-1]                      managedbuffer |           1 |    128     B
[2023-04-26 15:16:05,241: WARNING/ForkPoolWorker-1]                               list |           1 |     40     B
[2023-04-26 15:16:05,241: WARNING/ForkPoolWorker-1]                                int |          -1 |    -36     B
[2023-04-26 15:16:05,241: WARNING/ForkPoolWorker-1]            http.client.HTTPMessage |          -1 |    -48     B
[2023-04-26 15:16:05,242: WARNING/ForkPoolWorker-1]        sentry_sdk.profiler.Profile |          -1 |    -48     B
[2023-04-26 15:16:05,242: WARNING/ForkPoolWorker-1]           http.client.HTTPResponse |          -1 |    -48     B
[2023-04-26 15:16:05,242: WARNING/ForkPoolWorker-1]   sentry_sdk.tracing_utils.Baggage |          -1 |    -56     B
[2023-04-26 15:16:05,243: WARNING/ForkPoolWorker-1]         sentry_sdk.utils.ParsedUrl |          -1 |    -64     B
[2023-04-26 15:16:05,243: WARNING/ForkPoolWorker-1]                             method |          -1 |    -64     B
[2023-04-26 15:16:06,473: WARNING/ForkPoolWorker-1]                  datetime.datetime |          -3 |   -144     B
[2023-04-26 15:16:06,474: WARNING/ForkPoolWorker-1]            sentry_sdk.tracing.Span |          -1 |   -168     B
[2023-04-26 15:16:06,474: WARNING/ForkPoolWorker-1]                                str |          -4 |   -210     B
[2023-04-26 15:16:06,474: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1979996.0 Mb
[2023-04-26 15:16:08,357: INFO/ForkPoolWorker-1] Task person[985238a6-ddb5-4490-9bd0-2db8e95a0dc5] succeeded in 4.069310194001446s: None
[2023-04-26 15:16:09,311: WARNING/ForkPoolWorker-1]                        types |   # objects |    total size
[2023-04-26 15:16:09,312: WARNING/ForkPoolWorker-1] ============================ | =========== | =============
[2023-04-26 15:16:09,313: WARNING/ForkPoolWorker-1]                        tuple |          12 |     680     B
[2023-04-26 15:16:09,314: WARNING/ForkPoolWorker-1]                         dict |           3 |     480     B
[2023-04-26 15:16:09,314: WARNING/ForkPoolWorker-1]      sentry_sdk.tracing.Span |           1 |     168     B
[2023-04-26 15:16:09,314: WARNING/ForkPoolWorker-1]            datetime.datetime |           2 |      96     B
[2023-04-26 15:16:09,315: WARNING/ForkPoolWorker-1]   sentry_sdk.utils.ParsedUrl |           1 |      64     B
[2023-04-26 15:16:09,315: WARNING/ForkPoolWorker-1]      http.client.HTTPMessage |           1 |      48     B
[2023-04-26 15:16:09,316: WARNING/ForkPoolWorker-1]     http.client.HTTPResponse |           1 |      48     B
[2023-04-26 15:16:09,316: WARNING/ForkPoolWorker-1]                          str |           1 |      46     B
[2023-04-26 15:16:09,316: WARNING/ForkPoolWorker-1]                         list |          -1 |       0     B
[2023-04-26 15:16:09,317: WARNING/ForkPoolWorker-1]                          int |          -1 |     -24     B
[2023-04-26 15:16:09,317: WARNING/ForkPoolWorker-1]                managedbuffer |          -1 |    -128     B
[2023-04-26 15:16:09,318: WARNING/ForkPoolWorker-1]   builtin_function_or_method |          -2 |    -144     B
[2023-04-26 15:16:09,318: WARNING/ForkPoolWorker-1]                   memoryview |          -3 |    -552     B
[2023-04-26 15:16:09,318: WARNING/ForkPoolWorker-1]                        bytes |          -1 |   -1117     B
[2023-04-26 15:16:09,319: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1988440.0 Mb
[2023-04-26 15:16:11,135: INFO/ForkPoolWorker-1] Task person[6fc83679-e4fd-43c0-a8cc-e7bdb69a9147] succeeded in 2.7742452140009846s: None
```

</details>

---

<details>
<summary> with profiling </summary>

```
[2023-04-26 15:25:59,859: INFO/ForkPoolWorker-1] Task person[cc9a4bc0-46db-46b4-8ebe-4662664ac45a] succeeded in 3.2441984829965804s: None
[2023-04-26 15:26:00,884: WARNING/ForkPoolWorker-1]                              types |   # objects |   total size
[2023-04-26 15:26:00,884: WARNING/ForkPoolWorker-1] ================================== | =========== | ============
[2023-04-26 15:26:00,884: WARNING/ForkPoolWorker-1]                               dict |         963 |    283.78 KB
[2023-04-26 15:26:00,885: WARNING/ForkPoolWorker-1]                                str |        1424 |    112.75 KB
[2023-04-26 15:26:00,886: WARNING/ForkPoolWorker-1]                              bytes |           9 |     99.23 KB
[2023-04-26 15:26:00,886: WARNING/ForkPoolWorker-1]                               code |         424 |     73.38 KB
[2023-04-26 15:26:00,887: WARNING/ForkPoolWorker-1]                               list |         566 |     66.57 KB
[2023-04-26 15:26:00,887: WARNING/ForkPoolWorker-1]                               type |          55 |     61.43 KB
[2023-04-26 15:26:00,888: WARNING/ForkPoolWorker-1]                                set |          17 |     34.09 KB
[2023-04-26 15:26:00,888: WARNING/ForkPoolWorker-1]                              tuple |         297 |     17.94 KB
[2023-04-26 15:26:00,888: WARNING/ForkPoolWorker-1]                                int |         421 |     11.81 KB
[2023-04-26 15:26:00,889: WARNING/ForkPoolWorker-1]   redis.client.CaseInsensitiveDict |           1 |      9.11 KB
[2023-04-26 15:26:00,889: WARNING/ForkPoolWorker-1]              weakref.ReferenceType |          94 |      6.61 KB
[2023-04-26 15:26:00,889: WARNING/ForkPoolWorker-1]                  collections.deque |           6 |      4.17 KB
[2023-04-26 15:26:00,890: WARNING/ForkPoolWorker-1]                function (__init__) |          24 |      3.38 KB
[2023-04-26 15:26:00,890: WARNING/ForkPoolWorker-1]         builtin_function_or_method |          44 |      3.09 KB
[2023-04-26 15:26:00,891: WARNING/ForkPoolWorker-1]                               cell |          68 |      2.66 KB
[2023-04-26 15:26:00,891: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1961144.0 Mb
[2023-04-26 15:26:02,569: INFO/ForkPoolWorker-1] Task person[6c4e7fde-b8b9-4fdd-bc44-4e764391a1e3] succeeded in 2.703739421998762s: None
[2023-04-26 15:26:03,556: WARNING/ForkPoolWorker-1]                            types |   # objects |   total size
[2023-04-26 15:26:03,556: WARNING/ForkPoolWorker-1] ================================ | =========== | ============
[2023-04-26 15:26:03,557: WARNING/ForkPoolWorker-1]                             dict |         762 |    186.22 KB
[2023-04-26 15:26:03,558: WARNING/ForkPoolWorker-1]                             list |         280 |     37.65 KB
[2023-04-26 15:26:03,558: WARNING/ForkPoolWorker-1]                              str |         256 |     18.56 KB
[2023-04-26 15:26:03,559: WARNING/ForkPoolWorker-1]                            bytes |          -1 |     14.03 KB
[2023-04-26 15:26:03,559: WARNING/ForkPoolWorker-1]                      _io.BytesIO |           1 |      7.58 KB
[2023-04-26 15:26:03,560: WARNING/ForkPoolWorker-1]                              int |          95 |      2.62 KB
[2023-04-26 15:26:03,560: WARNING/ForkPoolWorker-1]                collections.deque |           4 |      2.44 KB
[2023-04-26 15:26:03,560: WARNING/ForkPoolWorker-1]                            tuple |          19 |      1.12 KB
[2023-04-26 15:26:03,561: WARNING/ForkPoolWorker-1]                       re.Pattern |           2 |    556     B
[2023-04-26 15:26:03,561: WARNING/ForkPoolWorker-1]                             code |           0 |    517     B
[2023-04-26 15:26:03,562: WARNING/ForkPoolWorker-1]       builtin_function_or_method |           7 |    504     B
[2023-04-26 15:26:03,562: WARNING/ForkPoolWorker-1]                       memoryview |           2 |    368     B
[2023-04-26 15:26:03,562: WARNING/ForkPoolWorker-1]      urllib3.poolmanager.PoolKey |           1 |    248     B
[2023-04-26 15:26:03,563: WARNING/ForkPoolWorker-1]   sentry_sdk.tracing.Transaction |           1 |    232     B
[2023-04-26 15:26:03,563: WARNING/ForkPoolWorker-1]                 <enum 'Options'> |           4 |    184     B
[2023-04-26 15:26:03,564: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1974340.0 Mb
[2023-04-26 15:26:05,203: INFO/ForkPoolWorker-1] Task person[cb3c70f7-c0f7-439d-a401-e0503e7733e5] succeeded in 2.627798260997224s: None
[2023-04-26 15:26:06,203: WARNING/ForkPoolWorker-1]                        types |   # objects |   total size
[2023-04-26 15:26:06,205: WARNING/ForkPoolWorker-1] ============================ | =========== | ============
[2023-04-26 15:26:06,205: WARNING/ForkPoolWorker-1]                         dict |          42 |     14.00 KB
[2023-04-26 15:26:06,206: WARNING/ForkPoolWorker-1]                        bytes |           1 |      3.98 KB
[2023-04-26 15:26:06,207: WARNING/ForkPoolWorker-1]                         list |          22 |      2.77 KB
[2023-04-26 15:26:06,208: WARNING/ForkPoolWorker-1]                          str |          31 |      2.18 KB
[2023-04-26 15:26:06,209: WARNING/ForkPoolWorker-1]                        tuple |          25 |      1.50 KB
[2023-04-26 15:26:06,209: WARNING/ForkPoolWorker-1]                         code |           1 |    680     B
[2023-04-26 15:26:06,210: WARNING/ForkPoolWorker-1]            collections.deque |           1 |    624     B
[2023-04-26 15:26:06,210: WARNING/ForkPoolWorker-1]                         cell |          11 |    440     B
[2023-04-26 15:26:06,210: WARNING/ForkPoolWorker-1]          function (<lambda>) |           2 |    288     B
[2023-04-26 15:26:06,211: WARNING/ForkPoolWorker-1]            datetime.datetime |           5 |    240     B
[2023-04-26 15:26:06,211: WARNING/ForkPoolWorker-1]                  _io.BytesIO |          -1 |    183     B
[2023-04-26 15:26:06,212: WARNING/ForkPoolWorker-1]       sentry_sdk.scope.Scope |           1 |    176     B
[2023-04-26 15:26:06,212: WARNING/ForkPoolWorker-1]      sentry_sdk.tracing.Span |           1 |    168     B
[2023-04-26 15:26:06,213: WARNING/ForkPoolWorker-1]   function (event_processor) |           1 |    144     B
[2023-04-26 15:26:06,213: WARNING/ForkPoolWorker-1]      http.client.HTTPMessage |           1 |     48     B
[2023-04-26 15:26:06,214: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1982684.0 Mb
[2023-04-26 15:26:07,859: INFO/ForkPoolWorker-1] Task person[e0640bed-4357-40b2-b120-017ec440b6c4] succeeded in 2.6505720760033s: None
[2023-04-26 15:26:08,855: WARNING/ForkPoolWorker-1]               types |   # objects |   total size
[2023-04-26 15:26:08,857: WARNING/ForkPoolWorker-1] =================== | =========== | ============
[2023-04-26 15:26:08,857: WARNING/ForkPoolWorker-1]   collections.deque |           3 |      2.34 KB
[2023-04-26 15:26:08,858: WARNING/ForkPoolWorker-1]               tuple |          15 |      1.22 KB
[2023-04-26 15:26:08,859: WARNING/ForkPoolWorker-1]                dict |           7 |    832     B
[2023-04-26 15:26:08,859: WARNING/ForkPoolWorker-1]                 set |           0 |    256     B
[2023-04-26 15:26:08,860: WARNING/ForkPoolWorker-1]                 int |           8 |    256     B
[2023-04-26 15:26:08,860: WARNING/ForkPoolWorker-1]               bytes |           0 |    204     B
[2023-04-26 15:26:08,861: WARNING/ForkPoolWorker-1]                 str |           1 |     50     B
[2023-04-26 15:26:08,861: WARNING/ForkPoolWorker-1]         _io.BytesIO |           0 |     29     B
[2023-04-26 15:26:08,862: WARNING/ForkPoolWorker-1]       list_iterator |          -1 |    -48     B
[2023-04-26 15:26:08,862: WARNING/ForkPoolWorker-1]                list |          -2 |   -896     B
[2023-04-26 15:26:08,863: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1986888.0 Mb
[2023-04-26 15:26:10,502: INFO/ForkPoolWorker-1] Task person[1512895d-edcb-42a7-9abb-b1ba7098b3f3] succeeded in 2.635894773000473s: None
```

</details>
ok hmm, seems `ru_maxrss` has different semantics on linux and mac 
next I tried an explicit `gc.collect()` with profiling on, also seeing very different behaviour
there's much slower growth then

@Zylphrex would you say this is just the global `_scheduler` object or is there something else going on here?

```python
@app.task(name="person")
def do_task(
        message: str,
):
    gc.collect()
    memory_consumed = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    print(f"Memory ar the beginning of the task: {memory_consumed / (2**20)} Mb")
    a = [np.random.random((4000, 4000, 3)) for i in range(5)]
```

<details>

<summary> 
with gc collect in each task

</summary>

```
[2023-04-26 17:26:05,170: INFO/ForkPoolWorker-1] Task person[519a9e27-20e6-4ad8-a057-74d11a33dbfe] succeeded in 2.3043774479992862s: None
[2023-04-26 17:26:05,178: INFO/MainProcess] Task person[3d6841e5-b589-4b86-a2e4-07e8a4d689e8] received
[2023-04-26 17:26:05,285: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1871.48046875 Mb
[2023-04-26 17:26:06,963: INFO/ForkPoolWorker-1] Task person[45564e65-34b4-4640-b5ed-c682d6a9717c] succeeded in 1.7869391400017776s: None
[2023-04-26 17:26:06,972: INFO/MainProcess] Task person[7131edf9-f709-4f09-9879-37bc4f947777] received
[2023-04-26 17:26:07,060: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1874.9609375 Mb
[2023-04-26 17:26:08,754: INFO/ForkPoolWorker-1] Task person[b88318c8-9c60-476c-b321-f7cdb5de209c] succeeded in 1.784490519999963s: None
[2023-04-26 17:26:08,764: INFO/MainProcess] Task person[b0cf7462-03d3-452d-82ed-bfd3b1e6f597] received
[2023-04-26 17:26:08,851: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1875.21875 Mb
[2023-04-26 17:26:10,518: INFO/ForkPoolWorker-1] Task person[85d43731-c6de-4eda-baae-7526ac8de601] succeeded in 1.756535114000144s: None
[2023-04-26 17:26:10,526: INFO/MainProcess] Task person[879c4e25-9a74-43af-b5ca-47170476ca62] received
[2023-04-26 17:26:10,616: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1875.48828125 Mb
[2023-04-26 17:26:12,234: INFO/ForkPoolWorker-1] Task person[27a6c875-9ec2-4ea9-91b4-c3dad20bfb37] succeeded in 1.7105341640017286s: None
[2023-04-26 17:26:12,242: INFO/MainProcess] Task person[edfc32ce-1525-4c9f-9ae0-b30ab6811c2e] received
[2023-04-26 17:26:12,256: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1875.73046875 Mb
[2023-04-26 17:26:14,469: INFO/ForkPoolWorker-1] Task person[3d6841e5-b589-4b86-a2e4-07e8a4d689e8] succeeded in 2.229374086997268s: None
[2023-04-26 17:26:14,478: INFO/MainProcess] Task person[423f6c38-c9ca-4ece-a651-d69cedfc0428] received
[2023-04-26 17:26:14,654: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3707.16796875 Mb
[2023-04-26 17:26:16,351: INFO/ForkPoolWorker-1] Task person[7131edf9-f709-4f09-9879-37bc4f947777] succeeded in 1.875419834999775s: None
[2023-04-26 17:26:16,359: INFO/MainProcess] Task person[7adb7af9-cc0b-404a-a564-480299072dd4] received
[2023-04-26 17:26:16,448: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3707.484375 Mb
[2023-04-26 17:26:18,082: INFO/ForkPoolWorker-1] Task person[b0cf7462-03d3-452d-82ed-bfd3b1e6f597] succeeded in 1.7258147600005032s: None
[2023-04-26 17:26:18,092: INFO/MainProcess] Task person[9dfed017-6440-4af7-b60a-b8a6bb2b1cb8] received
[2023-04-26 17:26:18,183: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3707.7734375 Mb
[2023-04-26 17:26:19,819: INFO/ForkPoolWorker-1] Task person[879c4e25-9a74-43af-b5ca-47170476ca62] succeeded in 1.7291307100022095s: None
[2023-04-26 17:26:19,827: INFO/MainProcess] Task person[08050623-9dab-4928-99de-e1ecd745e685] received
[2023-04-26 17:26:19,915: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3707.78515625 Mb
[2023-04-26 17:26:21,607: INFO/ForkPoolWorker-1] Task person[edfc32ce-1525-4c9f-9ae0-b30ab6811c2e] succeeded in 1.7822402349993354s: None
[2023-04-26 17:26:21,615: INFO/MainProcess] Task person[6fd8604c-561f-44ab-9b6e-39b98cba6585] received
[2023-04-26 17:26:21,703: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3707.86328125 Mb
[2023-04-26 17:26:23,330: INFO/ForkPoolWorker-1] Task person[423f6c38-c9ca-4ece-a651-d69cedfc0428] succeeded in 1.7172703249998449s: None
[2023-04-26 17:26:23,339: INFO/MainProcess] Task person[6fc545a2-243b-4f2c-98e7-c9fa385c6f00] received
[2023-04-26 17:26:23,428: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3707.90234375 Mb
[2023-04-26 17:26:25,054: INFO/ForkPoolWorker-1] Task person[7adb7af9-cc0b-404a-a564-480299072dd4] succeeded in 1.7176586669993412s: None
[2023-04-26 17:26:25,062: INFO/MainProcess] Task person[25616108-0234-4d37-b6ad-b51ae77e13e6] received
[2023-04-26 17:26:25,151: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.1484375 Mb
[2023-04-26 17:26:26,789: INFO/ForkPoolWorker-1] Task person[9dfed017-6440-4af7-b60a-b8a6bb2b1cb8] succeeded in 1.7291531990013027s: None
[2023-04-26 17:26:26,797: INFO/MainProcess] Task person[dd1a482c-6936-46e5-826b-21ef08e072f8] received
[2023-04-26 17:26:26,885: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.31640625 Mb
[2023-04-26 17:26:28,492: INFO/ForkPoolWorker-1] Task person[08050623-9dab-4928-99de-e1ecd745e685] succeeded in 1.6978322570030286s: None
[2023-04-26 17:26:28,500: INFO/MainProcess] Task person[6a959080-7eba-479e-9f03-7a513f1605ca] received
[2023-04-26 17:26:28,514: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.3203125 Mb
[2023-04-26 17:26:30,162: INFO/ForkPoolWorker-1] Task person[6fd8604c-561f-44ab-9b6e-39b98cba6585] succeeded in 1.6641478310011735s: None
[2023-04-26 17:26:30,171: INFO/MainProcess] Task person[7cf83a7b-9fa7-460e-87ee-aa18b772857f] received
[2023-04-26 17:26:30,330: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.3359375 Mb
[2023-04-26 17:26:31,963: INFO/ForkPoolWorker-1] Task person[6fc545a2-243b-4f2c-98e7-c9fa385c6f00] succeeded in 1.7948683470021933s: None
[2023-04-26 17:26:32,063: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.3359375 Mb
[2023-04-26 17:26:33,706: INFO/ForkPoolWorker-1] Task person[25616108-0234-4d37-b6ad-b51ae77e13e6] succeeded in 1.735856713999965s: None
[2023-04-26 17:26:33,802: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.41015625 Mb
[2023-04-26 17:26:35,451: INFO/ForkPoolWorker-1] Task person[dd1a482c-6936-46e5-826b-21ef08e072f8] succeeded in 1.7389370060009242s: None
[2023-04-26 17:26:35,548: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.41015625 Mb
[2023-04-26 17:26:37,197: INFO/ForkPoolWorker-1] Task person[6a959080-7eba-479e-9f03-7a513f1605ca] succeeded in 1.7402558220019273s: None
[2023-04-26 17:26:37,295: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3708.43359375 Mb
[2023-04-26 17:26:38,909: INFO/ForkPoolWorker-1] Task person[7cf83a7b-9fa7-460e-87ee-aa18b772857f] succeeded in 1.7066584230014996s: None
```

</details>

---

<details>
<summary> without gc collect </summary>

```
[2023-04-26 17:26:59,805: INFO/ForkPoolWorker-1] Task person[ee5a25a3-fe38-41f9-ac68-fdeb759bc2fa] succeeded in 2.408651669000392s: None
[2023-04-26 17:26:59,813: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 1851.953125 Mb
[2023-04-26 17:26:59,815: INFO/MainProcess] Task person[a52689f8-c40f-4ad5-8519-76c036207216] received
[2023-04-26 17:27:01,783: INFO/ForkPoolWorker-1] Task person[9b70df3b-67fa-419a-aaa9-9dcd2daa2f97] succeeded in 1.9700136940009543s: None
[2023-04-26 17:27:01,789: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 2590.00390625 Mb
[2023-04-26 17:27:01,792: INFO/MainProcess] Task person[89aace2e-dcee-4264-a0cf-97118126bc1a] received
[2023-04-26 17:27:03,937: INFO/ForkPoolWorker-1] Task person[67f70a67-5de5-49d8-8024-e39eb6751909] succeeded in 2.1478632209982607s: None
[2023-04-26 17:27:03,943: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 3689.22265625 Mb
[2023-04-26 17:27:03,945: INFO/MainProcess] Task person[217d197c-a9cf-4bc2-87c7-238536327821] received
[2023-04-26 17:27:06,336: INFO/ForkPoolWorker-1] Task person[8f09db42-b47a-4c9e-b709-64934be52e2c] succeeded in 2.393061968999973s: None
[2023-04-26 17:27:06,343: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 5520.99609375 Mb
[2023-04-26 17:27:06,345: INFO/MainProcess] Task person[4d5af51c-d8ac-484f-a3f8-9e313a1078ac] received
[2023-04-26 17:27:08,614: INFO/ForkPoolWorker-1] Task person[2b924f0d-39e5-42ce-becf-2085943efbd8] succeeded in 2.2718035590005456s: None
[2023-04-26 17:27:08,621: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 6619.9375 Mb
[2023-04-26 17:27:08,623: INFO/MainProcess] Task person[dbafec8c-a8c1-47d8-a0fd-96098dbcc1aa] received
[2023-04-26 17:27:10,394: INFO/ForkPoolWorker-1] Task person[a52689f8-c40f-4ad5-8519-76c036207216] succeeded in 1.7734061880000809s: None
[2023-04-26 17:27:10,400: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 6620.15625 Mb
[2023-04-26 17:27:10,403: INFO/MainProcess] Task person[10a79a99-957e-423b-899b-abfcc5510b8a] received
[2023-04-26 17:27:13,281: INFO/ForkPoolWorker-1] Task person[89aace2e-dcee-4264-a0cf-97118126bc1a] succeeded in 2.8810131430000183s: None
[2023-04-26 17:27:13,291: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 7353.18359375 Mb
[2023-04-26 17:27:13,296: INFO/MainProcess] Task person[3d96c624-0444-438f-8197-9a4e3a1746d5] received
[2023-04-26 17:27:15,788: INFO/ForkPoolWorker-1] Task person[217d197c-a9cf-4bc2-87c7-238536327821] succeeded in 2.4973450580000645s: None
[2023-04-26 17:27:15,799: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 9184.41015625 Mb
[2023-04-26 17:27:15,802: INFO/MainProcess] Task person[01dd6b97-0a3a-47a8-b071-a290172d49e7] received
[2023-04-26 17:27:17,525: INFO/ForkPoolWorker-1] Task person[4d5af51c-d8ac-484f-a3f8-9e313a1078ac] succeeded in 1.7265114440015168s: None
[2023-04-26 17:27:17,531: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 9184.62890625 Mb
[2023-04-26 17:27:17,533: INFO/MainProcess] Task person[58a2c91c-4efa-4cac-ad12-4639c685cde9] received
[2023-04-26 17:27:19,237: INFO/ForkPoolWorker-1] Task person[dbafec8c-a8c1-47d8-a0fd-96098dbcc1aa] succeeded in 1.7063713800016558s: None
[2023-04-26 17:27:19,243: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 9184.7265625 Mb
[2023-04-26 17:27:19,245: INFO/MainProcess] Task person[11804cb9-f1a2-46eb-b5c6-4a4e272b9951] received
[2023-04-26 17:27:21,771: INFO/ForkPoolWorker-1] Task person[10a79a99-957e-423b-899b-abfcc5510b8a] succeeded in 2.5279170450012316s: None
[2023-04-26 17:27:21,776: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11016.33984375 Mb
[2023-04-26 17:27:21,778: INFO/MainProcess] Task person[67b8aafa-be58-49f0-9ed1-98839e99fb8b] received
[2023-04-26 17:27:24,323: INFO/ForkPoolWorker-1] Task person[3d96c624-0444-438f-8197-9a4e3a1746d5] succeeded in 2.547209620999638s: None
[2023-04-26 17:27:24,329: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:24,331: INFO/MainProcess] Task person[311228b0-4e60-4a59-b5ce-a728d1e9a5de] received
[2023-04-26 17:27:26,440: INFO/ForkPoolWorker-1] Task person[01dd6b97-0a3a-47a8-b071-a290172d49e7] succeeded in 2.111017297000217s: None
[2023-04-26 17:27:26,447: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:26,449: INFO/MainProcess] Task person[9b7134f7-61f4-492c-bc8d-c8fdef932654] received
[2023-04-26 17:27:28,071: INFO/ForkPoolWorker-1] Task person[58a2c91c-4efa-4cac-ad12-4639c685cde9] succeeded in 1.6246286739988136s: None
[2023-04-26 17:27:28,079: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:28,081: INFO/MainProcess] Task person[9e57efe9-445e-42ce-a408-e85c4a0a4b3a] received
[2023-04-26 17:27:31,854: INFO/ForkPoolWorker-1] Task person[11804cb9-f1a2-46eb-b5c6-4a4e272b9951] succeeded in 3.7757800559993484s: None
[2023-04-26 17:27:31,862: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:31,864: INFO/MainProcess] Task person[2a462661-98ee-43ad-91ab-e91eee97a2f6] received
[2023-04-26 17:27:33,519: INFO/ForkPoolWorker-1] Task person[67b8aafa-be58-49f0-9ed1-98839e99fb8b] succeeded in 1.6569068820026587s: None
[2023-04-26 17:27:33,525: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:36,223: INFO/ForkPoolWorker-1] Task person[311228b0-4e60-4a59-b5ce-a728d1e9a5de] succeeded in 2.6978715379991627s: None
[2023-04-26 17:27:36,252: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:39,624: INFO/ForkPoolWorker-1] Task person[9b7134f7-61f4-492c-bc8d-c8fdef932654] succeeded in 3.3715391800033103s: None
[2023-04-26 17:27:39,631: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:41,426: INFO/ForkPoolWorker-1] Task person[9e57efe9-445e-42ce-a408-e85c4a0a4b3a] succeeded in 1.794912707999174s: None
[2023-04-26 17:27:41,432: WARNING/ForkPoolWorker-1] Memory ar the beginning of the task: 11514.48828125 Mb
[2023-04-26 17:27:44,212: INFO/ForkPoolWorker-1] Task person[2a462661-98ee-43ad-91ab-e91eee97a2f6] succeeded in 2.7798814449997735s: None
^C
```

</details>



I've tracked it down to this commit https://github.com/getsentry/sentry-python/pull/1903 as the one that introduced this leak. I'm not sure what the problem is yet but I'll update once I have more information.

Resolving patch:
diff --git a/sentry_sdk/_lru_cache.py b/sentry_sdk/_lru_cache.py
new file mode 100644
--- /dev/null
+++ b/sentry_sdk/_lru_cache.py
@@ -0,0 +1,156 @@
+"""
+A fork of Python 3.6's stdlib lru_cache (found in Python's 'cpython/Lib/functools.py')
+adapted into a data structure for single threaded uses.
+
+https://github.com/python/cpython/blob/v3.6.12/Lib/functools.py
+
+
+Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
+
+All Rights Reserved
+
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
+All Rights Reserved" are retained in Python alone or in any derivative version
+prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee.  This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+"""
+
+SENTINEL = object()
+
+
+# aliases to the entries in a node
+PREV = 0
+NEXT = 1
+KEY = 2
+VALUE = 3
+
+
+class LRUCache(object):
+    def __init__(self, max_size):
+        assert max_size > 0
+
+        self.max_size = max_size
+        self.full = False
+
+        self.cache = {}
+
+        # root of the circularly linked list to keep track of
+        # the least recently used key
+        self.root = []  # type: ignore
+        # the node looks like [PREV, NEXT, KEY, VALUE]
+        self.root[:] = [self.root, self.root, None, None]
+
+        self.hits = self.misses = 0
+
+    def set(self, key, value):
+        link = self.cache.get(key, SENTINEL)
+
+        if link is not SENTINEL:
+            # have to move the node to the front of the linked list
+            link_prev, link_next, _key, _value = link
+
+            # first remove the node from the lsnked list
+            link_prev[NEXT] = link_next
+            link_next[PREV] = link_prev
+
+            # insert the node between the root and the last
+            last = self.root[PREV]
+            last[NEXT] = self.root[PREV] = link
+            link[PREV] = last
+            link[NEXT] = self.root
+
+            # update the value
+            link[VALUE] = value
+
+        elif self.full:
+            # reuse the root node, so update its key/value
+            old_root = self.root
+            old_root[KEY] = key
+            old_root[VALUE] = value
+
+            self.root = old_root[NEXT]
+            old_key = self.root[KEY]
+
+            self.root[KEY] = self.root[VALUE] = None
+
+            del self.cache[old_key]
+
+            self.cache[key] = old_root
+
+        else:
+            # insert new node after last
+            last = self.root[PREV]
+            link = [last, self.root, key, value]
+            last[NEXT] = self.root[PREV] = self.cache[key] = link
+            self.full = len(self.cache) >= self.max_size
+
+    def get(self, key, default=None):
+        link = self.cache.get(key, SENTINEL)
+
+        if link is SENTINEL:
+            self.misses += 1
+            return default
+
+        # have to move the node to the front of the linked list
+        link_prev, link_next, _key, _value = link
+
+        # first remove the node from the lsnked list
+        link_prev[NEXT] = link_next
+        link_next[PREV] = link_prev
+
+        # insert the node between the root and the last
+        last = self.root[PREV]
+        last[NEXT] = self.root[PREV] = link
+        link[PREV] = last
+        link[NEXT] = self.root
+
+        self.hits += 1
+
+        return link[VALUE]
diff --git a/sentry_sdk/profiler.py b/sentry_sdk/profiler.py
--- a/sentry_sdk/profiler.py
+++ b/sentry_sdk/profiler.py
@@ -37,6 +37,7 @@
 
 import sentry_sdk
 from sentry_sdk._compat import PY33, PY311
+from sentry_sdk._lru_cache import LRUCache
 from sentry_sdk._types import TYPE_CHECKING
 from sentry_sdk.utils import (
     capture_internal_exception,
@@ -65,19 +66,6 @@
 
     ThreadId = str
 
-    # The exact value of this id is not very meaningful. The purpose
-    # of this id is to give us a compact and unique identifier for a
-    # raw stack that can be used as a key to a dictionary so that it
-    # can be used during the sampled format generation.
-    RawStackId = Tuple[int, int]
-
-    RawFrame = Tuple[
-        str,  # abs_path
-        int,  # lineno
-    ]
-    RawStack = Tuple[RawFrame, ...]
-    RawSample = Sequence[Tuple[str, Tuple[RawStackId, RawStack, Deque[FrameType]]]]
-
     ProcessedSample = TypedDict(
         "ProcessedSample",
         {
@@ -120,6 +108,21 @@
         {"profile_id": str},
     )
 
+    FrameId = Tuple[
+        str,  # abs_path
+        int,  # lineno
+    ]
+    FrameIds = Tuple[FrameId, ...]
+
+    # The exact value of this id is not very meaningful. The purpose
+    # of this id is to give us a compact and unique identifier for a
+    # raw stack that can be used as a key to a dictionary so that it
+    # can be used during the sampled format generation.
+    StackId = Tuple[int, int]
+
+    ExtractedStack = Tuple[StackId, FrameIds, List[ProcessedFrame]]
+    ExtractedSample = Sequence[Tuple[ThreadId, ExtractedStack]]
+
 
 try:
     from gevent import get_hub as get_gevent_hub  # type: ignore
@@ -244,12 +247,16 @@ def teardown_profiler():
 MAX_STACK_DEPTH = 128
 
 
+CWD = os.getcwd()
+
+
 def extract_stack(
-    frame,  # type: Optional[FrameType]
-    prev_cache=None,  # type: Optional[Tuple[RawStackId, RawStack, Deque[FrameType]]]
+    raw_frame,  # type: Optional[FrameType]
+    cache,  # type: LRUCache
+    cwd=CWD,  # type: str
     max_stack_depth=MAX_STACK_DEPTH,  # type: int
 ):
-    # type: (...) -> Tuple[RawStackId, RawStack, Deque[FrameType]]
+    # type: (...) -> ExtractedStack
     """
     Extracts the stack starting the specified frame. The extracted stack
     assumes the specified frame is the top of the stack, and works back
@@ -259,31 +266,21 @@ def extract_stack(
     only the first `MAX_STACK_DEPTH` frames will be returned.
     """
 
-    frames = deque(maxlen=max_stack_depth)  # type: Deque[FrameType]
+    raw_frames = deque(maxlen=max_stack_depth)  # type: Deque[FrameType]
 
-    while frame is not None:
-        f_back = frame.f_back
-        frames.append(frame)
-        frame = f_back
+    while raw_frame is not None:
+        f_back = raw_frame.f_back
+        raw_frames.append(raw_frame)
+        raw_frame = f_back
 
-    if prev_cache is None:
-        stack = tuple(frame_key(frame) for frame in frames)
-    else:
-        _, prev_stack, prev_frames = prev_cache
-        prev_depth = len(prev_frames)
-        depth = len(frames)
-
-        # We want to match the frame found in this sample to the frames found in the
-        # previous sample. If they are the same (using the `is` operator), we can
-        # skip the expensive work of extracting the frame information and reuse what
-        # we extracted during the last sample.
-        #
-        # Make sure to keep in mind that the stack is ordered from the inner most
-        # from to the outer most frame so be careful with the indexing.
-        stack = tuple(
-            prev_stack[i] if i >= 0 and frame is prev_frames[i] else frame_key(frame)
-            for i, frame in zip(range(prev_depth - depth, prev_depth), frames)
-        )
+    frame_ids = tuple(frame_id(raw_frame) for raw_frame in raw_frames)
+    frames = []
+    for i, fid in enumerate(frame_ids):
+        frame = cache.get(fid)
+        if frame is None:
+            frame = extract_frame(raw_frames[i], cwd)
+            cache.set(fid, frame)
+        frames.append(frame)
 
     # Instead of mapping the stack into frame ids and hashing
     # that as a tuple, we can directly hash the stack.
@@ -296,14 +293,14 @@ def extract_stack(
     # To Reduce the likelihood of hash collisions, we include
     # the stack depth. This means that only stacks of the same
     # depth can suffer from hash collisions.
-    stack_id = len(stack), hash(stack)
+    stack_id = len(raw_frames), hash(frame_ids)
 
-    return stack_id, stack, frames
+    return stack_id, frame_ids, frames
 
 
-def frame_key(frame):
-    # type: (FrameType) -> RawFrame
-    return (frame.f_code.co_filename, frame.f_lineno)
+def frame_id(raw_frame):
+    # type: (FrameType) -> FrameId
+    return (raw_frame.f_code.co_filename, raw_frame.f_lineno)
 
 
 def extract_frame(frame, cwd):
@@ -472,8 +469,8 @@ def __init__(
         self.stop_ns = 0  # type: int
         self.active = False  # type: bool
 
-        self.indexed_frames = {}  # type: Dict[RawFrame, int]
-        self.indexed_stacks = {}  # type: Dict[RawStackId, int]
+        self.indexed_frames = {}  # type: Dict[FrameId, int]
+        self.indexed_stacks = {}  # type: Dict[StackId, int]
         self.frames = []  # type: List[ProcessedFrame]
         self.stacks = []  # type: List[ProcessedStack]
         self.samples = []  # type: List[ProcessedSample]
@@ -613,8 +610,8 @@ def __exit__(self, ty, value, tb):
 
         scope.profile = old_profile
 
-    def write(self, cwd, ts, sample, frame_cache):
-        # type: (str, int, RawSample, Dict[RawFrame, ProcessedFrame]) -> None
+    def write(self, ts, sample):
+        # type: (int, ExtractedSample) -> None
         if not self.active:
             return
 
@@ -630,23 +627,19 @@ def write(self, cwd, ts, sample, frame_cache):
 
         elapsed_since_start_ns = str(offset)
 
-        for tid, (stack_id, raw_stack, frames) in sample:
+        for tid, (stack_id, frame_ids, frames) in sample:
             try:
                 # Check if the stack is indexed first, this lets us skip
                 # indexing frames if it's not necessary
                 if stack_id not in self.indexed_stacks:
-                    for i, raw_frame in enumerate(raw_stack):
-                        if raw_frame not in self.indexed_frames:
-                            self.indexed_frames[raw_frame] = len(self.indexed_frames)
-                            processed_frame = frame_cache.get(raw_frame)
-                            if processed_frame is None:
-                                processed_frame = extract_frame(frames[i], cwd)
-                                frame_cache[raw_frame] = processed_frame
-                            self.frames.append(processed_frame)
+                    for i, frame_id in enumerate(frame_ids):
+                        if frame_id not in self.indexed_frames:
+                            self.indexed_frames[frame_id] = len(self.indexed_frames)
+                            self.frames.append(frames[i])
 
                     self.indexed_stacks[stack_id] = len(self.indexed_stacks)
                     self.stacks.append(
-                        [self.indexed_frames[raw_frame] for raw_frame in raw_stack]
+                        [self.indexed_frames[frame_id] for frame_id in frame_ids]
                     )
 
                 self.samples.append(
@@ -791,12 +784,7 @@ def make_sampler(self):
         # type: () -> Callable[..., None]
         cwd = os.getcwd()
 
-        # In Python3+, we can use the `nonlocal` keyword to rebind the value,
-        # but this is not possible in Python2. To get around this, we wrap
-        # the value in a list to allow updating this value each sample.
-        last_sample = [
-            {}
-        ]  # type: List[Dict[int, Tuple[RawStackId, RawStack, Deque[FrameType]]]]
+        cache = LRUCache(max_size=256)
 
         def _sample_stack(*args, **kwargs):
             # type: (*Any, **Any) -> None
@@ -808,7 +796,6 @@ def _sample_stack(*args, **kwargs):
             if not self.new_profiles and not self.active_profiles:
                 # make sure to clear the cache if we're not profiling so we dont
                 # keep a reference to the last stack of frames around
-                last_sample[0] = {}
                 return
 
             # This is the number of profiles we want to pop off.
@@ -824,27 +811,16 @@ def _sample_stack(*args, **kwargs):
             now = nanosecond_time()
 
             try:
-                raw_sample = {
-                    tid: extract_stack(frame, last_sample[0].get(tid))
+                sample = [
+                    (str(tid), extract_stack(frame, cache, cwd))
                     for tid, frame in sys._current_frames().items()
-                }
+                ]
             except AttributeError:
                 # For some reason, the frame we get doesn't have certain attributes.
                 # When this happens, we abandon the current sample as it's bad.
                 capture_internal_exception(sys.exc_info())
-
-                # make sure to clear the cache if something went wrong when extracting
-                # the stack so we dont keep a reference to the last stack of frames around
-                last_sample[0] = {}
-
                 return
 
-            # make sure to update the last sample so the cache has
-            # the most recent stack for better cache hits
-            last_sample[0] = raw_sample
-
-            sample = [(str(tid), data) for tid, data in raw_sample.items()]
-
             # Move the new profiles into the active_profiles set.
             #
             # We cannot directly add the to active_profiles set
@@ -860,11 +836,9 @@ def _sample_stack(*args, **kwargs):
 
             inactive_profiles = []
 
-            frame_cache = {}  # type: Dict[RawFrame, ProcessedFrame]
-
             for profile in self.active_profiles:
                 if profile.active:
-                    profile.write(cwd, now, sample, frame_cache)
+                    profile.write(now, sample)
                 else:
                     # If a thread is marked inactive, we buffer it
                     # to `inactive_profiles` so it can be removed.


Test patch:
diff --git a/tests/test_lru_cache.py b/tests/test_lru_cache.py
new file mode 100644
--- /dev/null
+++ b/tests/test_lru_cache.py
@@ -0,0 +1,37 @@
+import pytest
+
+from sentry_sdk._lru_cache import LRUCache
+
+
+@pytest.mark.parametrize("max_size", [-10, -1, 0])
+def test_illegal_size(max_size):
+    with pytest.raises(AssertionError):
+        LRUCache(max_size=max_size)
+
+
+def test_simple_set_get():
+    cache = LRUCache(1)
+    assert cache.get(1) is None
+    cache.set(1, 1)
+    assert cache.get(1) == 1
+
+
+def test_overwrite():
+    cache = LRUCache(1)
+    assert cache.get(1) is None
+    cache.set(1, 1)
+    assert cache.get(1) == 1
+    cache.set(1, 2)
+    assert cache.get(1) == 2
+
+
+def test_cache_eviction():
+    cache = LRUCache(3)
+    cache.set(1, 1)
+    cache.set(2, 2)
+    cache.set(3, 3)
+    assert cache.get(1) == 1
+    assert cache.get(2) == 2
+    cache.set(4, 4)
+    assert cache.get(3) is None
+    assert cache.get(4) == 4
diff --git a/tests/test_profiler.py b/tests/test_profiler.py
--- a/tests/test_profiler.py
+++ b/tests/test_profiler.py
@@ -20,6 +20,7 @@
     setup_profiler,
 )
 from sentry_sdk.tracing import Transaction
+from sentry_sdk._lru_cache import LRUCache
 from sentry_sdk._queue import Queue
 
 try:
@@ -472,35 +473,40 @@ def test_extract_stack_with_max_depth(depth, max_stack_depth, actual_depth):
 
     # increase the max_depth by the `base_stack_depth` to account
     # for the extra frames pytest will add
-    _, stack, frames = extract_stack(
-        frame, max_stack_depth=max_stack_depth + base_stack_depth
+    _, frame_ids, frames = extract_stack(
+        frame, LRUCache(max_size=1), max_stack_depth=max_stack_depth + base_stack_depth
     )
-    assert len(stack) == base_stack_depth + actual_depth
+    assert len(frame_ids) == base_stack_depth + actual_depth
     assert len(frames) == base_stack_depth + actual_depth
 
     for i in range(actual_depth):
-        assert get_frame_name(frames[i]) == "get_frame", i
+        assert frames[i]["function"] == "get_frame", i
 
     # index 0 contains the inner most frame on the stack, so the lamdba
     # should be at index `actual_depth`
     if sys.version_info >= (3, 11):
         assert (
-            get_frame_name(frames[actual_depth])
+            frames[actual_depth]["function"]
             == "test_extract_stack_with_max_depth.<locals>.<lambda>"
         ), actual_depth
     else:
-        assert get_frame_name(frames[actual_depth]) == "<lambda>", actual_depth
+        assert frames[actual_depth]["function"] == "<lambda>", actual_depth
 
 
-def test_extract_stack_with_cache():
-    frame = get_frame(depth=1)
-
-    prev_cache = extract_stack(frame)
-    _, stack1, _ = prev_cache
-    _, stack2, _ = extract_stack(frame, prev_cache)
-
-    assert len(stack1) == len(stack2)
-    for i, (frame1, frame2) in enumerate(zip(stack1, stack2)):
+@pytest.mark.parametrize(
+    ("frame", "depth"),
+    [(get_frame(depth=1), len(inspect.stack()))],
+)
+def test_extract_stack_with_cache(frame, depth):
+    # make sure cache has enough room or this test will fail
+    cache = LRUCache(max_size=depth)
+    _, _, frames1 = extract_stack(frame, cache)
+    _, _, frames2 = extract_stack(frame, cache)
+
+    assert len(frames1) > 0
+    assert len(frames2) > 0
+    assert len(frames1) == len(frames2)
+    for i, (frame1, frame2) in enumerate(zip(frames1, frames2)):
         # DO NOT use `==` for the assertion here since we are
         # testing for identity, and using `==` would test for
         # equality which would always pass since we're extract
@@ -629,9 +635,7 @@ def test_thread_scheduler_single_background_thread(scheduler_class):
 )
 @mock.patch("sentry_sdk.profiler.MAX_PROFILE_DURATION_NS", 1)
 def test_max_profile_duration_reached(scheduler_class):
-    sample = [("1", extract_stack(get_frame()))]
-
-    cwd = os.getcwd()
+    sample = [("1", extract_stack(get_frame(), LRUCache(max_size=1)))]
 
     with scheduler_class(frequency=1000) as scheduler:
         transaction = Transaction(sampled=True)
@@ -640,15 +644,15 @@ def test_max_profile_duration_reached(scheduler_class):
             assert profile.active
 
             # write a sample at the start time, so still active
-            profile.write(cwd, profile.start_ns + 0, sample, {})
+            profile.write(profile.start_ns + 0, sample)
             assert profile.active
 
             # write a sample at max time, so still active
-            profile.write(cwd, profile.start_ns + 1, sample, {})
+            profile.write(profile.start_ns + 1, sample)
             assert profile.active
 
             # write a sample PAST the max time, so now inactive
-            profile.write(cwd, profile.start_ns + 2, sample, {})
+            profile.write(profile.start_ns + 2, sample)
             assert not profile.active
 
 
@@ -675,8 +679,8 @@ def ensure_running(self):
 
 
 sample_stacks = [
-    extract_stack(get_frame(), max_stack_depth=1),
-    extract_stack(get_frame(), max_stack_depth=2),
+    extract_stack(get_frame(), LRUCache(max_size=1), max_stack_depth=1),
+    extract_stack(get_frame(), LRUCache(max_size=1), max_stack_depth=2),
 ]
 
 
@@ -706,7 +710,7 @@ def ensure_running(self):
         pytest.param(
             [(0, [("1", sample_stacks[0])])],
             {
-                "frames": [extract_frame(sample_stacks[0][2][0], os.getcwd())],
+                "frames": [sample_stacks[0][2][0]],
                 "samples": [
                     {
                         "elapsed_since_start_ns": "0",
@@ -725,7 +729,7 @@ def ensure_running(self):
                 (1, [("1", sample_stacks[0])]),
             ],
             {
-                "frames": [extract_frame(sample_stacks[0][2][0], os.getcwd())],
+                "frames": [sample_stacks[0][2][0]],
                 "samples": [
                     {
                         "elapsed_since_start_ns": "0",
@@ -750,8 +754,8 @@ def ensure_running(self):
             ],
             {
                 "frames": [
-                    extract_frame(sample_stacks[0][2][0], os.getcwd()),
-                    extract_frame(sample_stacks[1][2][0], os.getcwd()),
+                    sample_stacks[0][2][0],
+                    sample_stacks[1][2][0],
                 ],
                 "samples": [
                     {
@@ -785,7 +789,7 @@ def test_profile_processing(
                 # force the sample to be written at a time relative to the
                 # start of the profile
                 now = profile.start_ns + ts
-                profile.write(os.getcwd(), now, sample, {})
+                profile.write(now, sample)
 
             processed = profile.process()