GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-113055: Use pointer for interp->obmalloc state. by nascheme · Pull Request #113412 · python/cpython

Conversation

@nascheme

@nascheme nascheme commented Dec 22, 2023 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

For interpreters that share state with the main interpreter, this points to the same static memory structure. For interpreters with their own obmalloc state, it is heap allocated. Add free_obmalloc_arenas() which will free the obmalloc arenas and radix tree structures for interpreters with their own obmalloc state.

Note that the free is only done if obmalloc used blocks is zero. If some blocks are used, it's not safe to free the memory since some extension might still be using it.

  • Issue: Memory leak on executables embedded with 3.13 #113055

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@nascheme
Use pointer for interp->obmalloc state.
be17cfd
For interpreters that share state with the main interpreter, this points
to the same static memory structure.  For interpreters with their own
obmalloc state, it is heap allocated.  Add free_obmalloc_arenas() which
will free the obmalloc arenas and radix tree structures for interpreters
with their own obmalloc state.
@nascheme
nascheme requested a review from ericsnowcurrently December 22, 2023 21:26
@bedevere-app bedevere-app Bot added the awaiting core review label Dec 22, 2023
@bedevere-app bedevere-app Bot mentioned this pull request Dec 22, 2023
Memory leak on executables embedded with 3.13 #113055
Closed
@nascheme

nascheme commented Dec 22, 2023

Copy link
Copy Markdown
Member Author

This should improve the situtation for gh-113055. There will still be memory leaks if interpreters don't free their memory (or load extensions who don't free their memory). However, when the Py_RTFLAGS_USE_MAIN_OBMALLOC flag is set (the default, I think), the behaviour will be much like it was in 3.11. I.e. interpreters use the main interpreter obmalloc state.

The obmalloc state for the main interpreter is back to being a static structure in the BSS, as it was in 3.11. My guess is the get_state() function in obmalloc is a tiny bit faster, because there is no test branch in it. I didn't profile that yet though. I think get_state() will be fast enough that it doesn't matter.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme nascheme mentioned this pull request Dec 22, 2023
gh-113055: Fix memory leak of obmalloc state #113218
Closed
@nascheme
Update Tools/c-analyzer/cpython/ignored.tsv.
33e0adb
The obmalloc_state_main global is okay and should be ignored.
@nascheme

nascheme commented Dec 23, 2023

Copy link
Copy Markdown
Member Author

It looks like the performance different for get_state() is tiny. Before this change (from perf record and perf report):

perf_obmalloc_before

And after:

perf_obmalloc_ptr

The counts in the left hand column are then number of samples that hit that instruction. My quick-and-dirty benchmark was:

./Programs/_testembed test_repeated_init_exec "$(cat bench_embed.py)"

with bench_embed.py containing:

import unittest

for i in range(4):
    unittest.main('test.test_dict', verbosity=1, exit=False)
    unittest.main('test.test_decimal', verbosity=1, exit=False)
    unittest.main('test.test_generators', verbosity=1, exit=False)
    unittest.main('test.test_set', verbosity=1, exit=False)

I didn't build with LTO and PGO, that would change things a bit I would guess.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme

nascheme commented Dec 23, 2023

Copy link
Copy Markdown
Member Author

With PGO and LTO turned on, the code becomes quite jumbled up and hard to follow. _PyObject_Free() disappears from the profile because it gets inlined in a bunch of places. Looking at PyObject_GC_Del(), there are no samples for the instruction corresponding to return interp->obmalloc in get_state().

image

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@neonene

neonene commented Dec 23, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Non-debug builds have memory leaks on Windows even using 33e0adb. At least, _PyObject_Arena.free() seems to never be called in the insert_to_freepool function.

The same goes for Python 3.12.1 with/without this patch applied.

EDIT: Observed with test_repeated_simple_init

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@neonene

neonene commented Dec 23, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

_PyObject_Arena.free() seems to never be called in the insert_to_freepool function

Bisected to: ea2c001, which this PR does not fully affect on my non-debug build.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme
nascheme requested a review from pablogsal January 11, 2024 22:10
@nascheme

nascheme commented Jan 11, 2024

Copy link
Copy Markdown
Member Author

I think this PR should get merged. It should be safe and it reduces memory used by sub-interpreters that share the main interpreter obmalloc state. It also eliminates a memory leak in the case of sub-interpreters that don't share the state. See free_obmalloc_arenas(). This call is conditional, only if _PyInterpreterState_GetAllocatedBlocks() returns zero. A more aggressive but less safe approach would be to always call free_obmalloc_arenas(). We can decide on that after merging this change.

neonene reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland
erlend-aasland requested a review from vstinner January 11, 2024 22:58
@neonene

neonene commented Jan 14, 2024

Copy link
Copy Markdown
Contributor

@Yhg1s Any thoughts?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Jan 22, 2024

Copy link
Copy Markdown
Member

@ericsnowcurrently Have you reviewed this? Do you feel it's ready to be merged?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jan 22, 2024

Copy link
Copy Markdown
Member

I'm planning on taking a look in the next day or two.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ericsnowcurrently
ericsnowcurrently requested changes Jan 24, 2024
View reviewed changes

@ericsnowcurrently ericsnowcurrently left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this! I think this is basically right. I didn't see any correctness issues.

Clearly I did leave a bunch of comments, but it's mostly little things like alternate spellings, whether or not to statically initialize obmalloc_state_main, and whether or not we really have to make PyInterpreterState.obmalloc a pointer.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Include/internal/pycore_runtime_init.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Objects/obmalloc.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Python/pylifecycle.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Objects/obmalloc.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Objects/obmalloc.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Objects/obmalloc.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Include/internal/pycore_interp.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Python/pylifecycle.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Python/pylifecycle.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Python/pystate.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting changes and removed awaiting core review labels Jan 24, 2024
@bedevere-app

bedevere-app Bot commented Jan 24, 2024

Copy link
Copy Markdown

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jan 25, 2024

Copy link
Copy Markdown
Member

Also, weren't you considering freeing the blocks that don't have any objects in them any more, to reduce how much leaks?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jan 25, 2024

Copy link
Copy Markdown
Member

Also, what do you think our options are for backporting this to 3.12?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently ericsnowcurrently mentioned this pull request Jan 25, 2024
sub-interpreters: significant memory leak on shutdown #110411
Closed
@nascheme

nascheme commented Jan 26, 2024

Copy link
Copy Markdown
Member Author

I would prefer to use a pointer. I think it's cleaner/faster and I think the memory savings, while not huge, are non-trivial. On 64-bit platforms, struct _obmalloc_state is 256 kB. Most of that is the arena_map_root. If you allocate it in the BSS then typically only one entry of that array is actually used and so only one page of memory is actually resident. So typically 4 kB vs 256 kB. Also, every sub-interpreter that uses the main obmalloc state saves 256 kB of resident memory.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme

nascheme commented Jan 26, 2024

Copy link
Copy Markdown
Member Author

Also, what do you think our options are for backporting this to 3.12?

Possible but a little scary. It's not a lot of code but it changes behavior quite a bit. Up to the release manager, I guess. The number of people affected by the memory usage/leaks is likely to be really small. At least, that's my guess. So maybe they need to skip 3.12 and go from 3.11 to 3.13 it this is problem for them. @neonene might have another perspective.

neonene reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jan 26, 2024

Copy link
Copy Markdown
Member

I would prefer to use a pointer.

Sounds good.

FWIW, subinterpreters that use the main obmalloc state supported for backward compatibility, are already uncommon, and I expect they will be more so as we move forward. So I wouldn't worry about factoring them into the decision very much.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme

nascheme commented Jan 26, 2024

Copy link
Copy Markdown
Member Author

Also, weren't you considering freeing the blocks that don't have any objects in them any more, to reduce how much leaks?

That's an idea. A bit of code to do that but probably not horrible. Another idea would be to add an -X flag or something similar that would enable freeing of all obmalloc arenas, even if there is a non-zero in-use count. Embedding programs could set this if they want to eliminate the leaks and are prepared to deal with extensions that crash because of it.

If it is safe to enable gh-113601 then maybe it is safe to just free the arenas as well. I think the same logic applies although it seems more likely freeing the arenas would be more likely to trigger a use-after-free bug.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

nascheme and others added 2 commits January 26, 2024 10:39
@nascheme @ericsnowcurrently
Remove redundant init of .obmalloc member
f8a93d4
Co-authored-by: Eric Snow <[email protected]>
@nascheme
Code cleanup based on review feedback.
bbaffbe
- Remove 'runtime' argument.
- Remove 'initialized' and 'heap_allocated' members.
- Use _Py_IsMainInterpreter()
- Remove spurious whitespace change.
- Return -1 on error and 0 on success, as normal convention.
@nascheme

nascheme commented Jan 26, 2024

Copy link
Copy Markdown
Member Author

Thanks for the detailed review feedback. I think I've addressed all of your suggestions.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ericsnowcurrently
ericsnowcurrently approved these changes Jan 26, 2024
View reviewed changes

@ericsnowcurrently ericsnowcurrently left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Tools/c-analyzer/cpython/ignored.tsv Resolved

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting changes labels Jan 26, 2024
@ericsnowcurrently

ericsnowcurrently commented Jan 26, 2024

Copy link
Copy Markdown
Member

Thanks for doing this!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme @ericsnowcurrently
Update c-analyzer globals list.
17dfc42
Co-authored-by: Eric Snow <[email protected]>
@nascheme
nascheme merged commit 7a7bce5 into python:main Jan 27, 2024
@bedevere-app bedevere-app Bot removed the awaiting merge label Jan 27, 2024
@encukou encukou mentioned this pull request Jan 30, 2024
test_pendingcalls_threaded times out on Windows free-threading builds #114746
Closed
@ericsnowcurrently

ericsnowcurrently commented Feb 1, 2024

Copy link
Copy Markdown
Member

@Yhg1s, what are your thoughts on backporting this to 3.12?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
@nascheme @ericsnowcurrently @aisk
pythongh-113055: Use pointer for interp->obmalloc state (pythongh-113412
6369f19
)

For interpreters that share state with the main interpreter, this points
to the same static memory structure.  For interpreters with their own
obmalloc state, it is heap allocated.  Add free_obmalloc_arenas() which
will free the obmalloc arenas and radix tree structures for interpreters
with their own obmalloc state.

Co-authored-by: Eric Snow <[email protected]>
@trygveaa

trygveaa commented Mar 8, 2024

Copy link
Copy Markdown

This fixes a segfault happening with 3.12, so it would be great if this could be backported to 3.12. I posted more details about the crash in #116510.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently ericsnowcurrently mentioned this pull request Mar 19, 2024
CPython 3.12 embedded in WeeChat causes segfault on subsequent calls to Py_EndInterpreter #116510
Closed
@bacon-cheeseburger

bacon-cheeseburger commented May 1, 2024

Copy link
Copy Markdown

Just wanted to offer that this issue appears to impact Kodi, which has a considerable user base in the millions. The number of users affected by the problem could be quite substantial.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented May 1, 2024

Copy link
Copy Markdown
Member

ping @Yhg1s

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme nascheme mentioned this pull request May 6, 2024
[3.12]: gh-113055: Use pointer for interp->obmalloc state #118618
Closed
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
@nascheme @ericsnowcurrently @Glyphack
pythongh-113055: Use pointer for interp->obmalloc state (pythongh-113412
40ff495
)

For interpreters that share state with the main interpreter, this points
to the same static memory structure.  For interpreters with their own
obmalloc state, it is heap allocated.  Add free_obmalloc_arenas() which
will free the obmalloc arenas and radix tree structures for interpreters
with their own obmalloc state.

Co-authored-by: Eric Snow <[email protected]>
@ZeroIntensity ZeroIntensity mentioned this pull request Sep 16, 2024
Creating an ungodly amount of sub interpreters in a short amount of time causes memory debug assertions. #123134
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@ericsnowcurrently ericsnowcurrently ericsnowcurrently approved these changes
@pablogsal pablogsal Awaiting requested review from pablogsal
@vstinner vstinner Awaiting requested review from vstinner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@nascheme @neonene @gvanrossum @ericsnowcurrently @trygveaa @bacon-cheeseburger
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.