Skip to content

_multiprocessing leaks references when initialised multiple times #94382

Description

@kumaraditya303

By converting _multiprocessing to heap types, the module can be used in subinterpreters and does not leak memory when Python finalizes or when it is initialized multiple times. The converted heap types are not performance critical.

Current Memory leak at exit:

[170 refs, 71 blocks]

See PR #94336

Activity

  1. encukou commented on Jun 28, 2022

    @encukou
    Member

    It seems the leak is with SEM_VALUE_MAX, a static integer?
    That could be solved by a PyGetSetDef getter.

  2. erlend-aasland commented on Jun 28, 2022

    @erlend-aasland
    Contributor

    Repeating #94336 (comment): AFAICS, the multiprocessing types do not access global module state, so there should be no reason to convert them to heap types.

  3. kumaraditya303 commented on Jun 28, 2022

    @kumaraditya303
    ContributorAuthor

    It seems the leak is with SEM_VALUE_MAX, a static integer?

    Where is that declared static? I don't see how it is considered a static integer. I am happy to be wrong though.

  4. changed the title [-]Convert static types of _multiprocessing module to heap types[/-] [+]_multiprocessing leaks references when initialised multiple times[/+] on Jun 28, 2022
  5. erlend-aasland commented on Jun 28, 2022

    @erlend-aasland
    Contributor

    I changed the issue title. It seems to me that the issue is a ref leak. The proposed solution is converting types to heap types. IMO, the GitHub Issue title should reflect the problem, not necessary the solution.

  6. kumaraditya303 commented on Jun 28, 2022

    @kumaraditya303
    ContributorAuthor

    It seems to me that the issue is a ref leak.

    Do you have a fix that does not use heap types or private APIs but fixes the issue?

  7. encukou commented on Jun 28, 2022

    @encukou
    Member

    Ah, terminology. It's not C static, but it's always the same, and it's currently meant to be initialized only once (and it's not decref'd, so it leaks). You can't change the value from Python.

    Do you have a fix that does not use heap types or private APIs but fixes the issue?

    I can send one later today, if nothing comes up.

  8. kumaraditya303 commented on Jun 28, 2022

    @kumaraditya303
    ContributorAuthor

    I can send one later today, if nothing comes up.

    Sure, please add me as a reviewer, I'll learn something new.

  9. encukou commented on Jun 28, 2022

    @encukou
    Member

    OK, I see now that the leak is not caused by SEM_VALUE_MAX, but (mostly?) by the method/getter/setter wrappers set by PyType_Ready.
    It seems to me that these are harmless: they won't be created a second time when _multiprocessing is imported again, and they can be reused in other interpreters. OTOH, they are flagged by -X showrefcount, and it would be nice to get those numbers to zero so -X showrefcount is useful in flagging new issues.

    @vstinner, are you aware of this issue with -X showrefcount and static types with methods/getters/setters?

  10. encukou commented on Jun 28, 2022

    @encukou
    Member

    In any case, the module state is unnecessary here.

  11. 23 remaining items

  12. kumaraditya303 commented on Jul 1, 2022

    @kumaraditya303
    ContributorAuthor

    For heap type conversion, PEP-687 explicitly applies to the following modules, as they contain types that access module state:
    Modules/_asynciomodule.c
    Modules/_ctypes/_ctypes.c
    Modules/_datetimemodule.c
    Modules/_decimal/_decimal.c
    Modules/_pickle.c
    Modules/_zoneinfo.c
    Maybe I missed a module.

    Thanks Erlend for the list but it would have been better if the PEP had explicitly mentioned this list.

    If there is no general consensus we can ping the SC. Either by asking them for advice, or by submitting another PEP for such issues.

    This is what I was trying to say if there is no general agreement, we can ask the SC for decision/advice.

  13. erlend-aasland commented on Jul 1, 2022

    @erlend-aasland
    Contributor

    This is what I was trying to say if there is no general agreement, we can ask the SC for decision/advice

    Perhaps there is a misunderstanding about what "general agreement" means. If this group (those involved on this issue) reach an agreement, that is not a "general agreement". A general agreement can only be reached amongst all core devs. Thus, the next level is creating a topic on Discourse, as has been mentioned multiple times already.

  14. kumaraditya303 commented on Jul 1, 2022

    @kumaraditya303
    ContributorAuthor

    @erlend-aasland: I'll create a discourse topic to discuss to this soon.

    Also, I apologies incase any of my wording sounded a bit rude but it was not my intension to hurt anyone here.

  15. encukou commented on Jul 1, 2022

    @encukou
    Member

    Hi,
    I agree that the change looks good from what I know now, but I don't think I (or any other single person) should make the decision.
    As Victor wrote:

    Things changed multiple times, I failed to keep track of these issues. But well, there are complex issues ;-)

    For complex issues, we have the PEP process. It's not just for getting agreement, but also for untangling/explaining the complexity. And while this change is small enough that a full PEP might not be needed, IMO it does need a clear explanation of what's wrong and why heap types are the best solution. And perhaps we'll not get there with just a discussion thread.
    This is not fixing a bug that users are seeing. It's a trade-off between correctness/maintainability and (percieved?) performance. There might be other issues we're not seeing.

    (FWIW, I also fail to keep track of these issues, as you can see from the fact that this was not covered in the PEP.)

  16. kumaraditya303 commented on Jul 1, 2022

    @kumaraditya303
    ContributorAuthor
  17. encukou commented on Jul 1, 2022

    @encukou
    Member

    In the topic you still say this is a problem for embedders and multiple interpreters aka subinterpreters which in embedding case will leak memory whenever Python is initialized and finalized one or more times in the same process, while I still think the extra memory gets allocated only once per process. Am I wrong? Could you show a case where there is an unlimited memory leak?

  18. kumaraditya303 commented on Jul 2, 2022

    @kumaraditya303
    ContributorAuthor

    Am I wrong? Could you show a case where there is an unlimited memory leak?

    Note that memory leak is much less in Python 3.12 and 3.11 as the runtime finalization even clears static types.
    I have seen more complicated cases where gc is involved and if the object survives after its interpreter is freed.

    from test import support
    import sys
    for i in range(1, 10):
        support.run_in_subinterp("import multiprocessing")
        print("refs:", sys.gettotalrefcount(), "blocks: ", sys.getallocatedblocks())

    Even if we consider the case for multiple finalization is less important still python leaks memory at exit even if it is initialized only once. Let's continue the discussion on discourse.

  19. vstinner commented on Jul 3, 2022

    @vstinner
    Member

    Output of the script:

    refs: 161895 blocks:  47464
    refs: 161958 blocks:  47484
    refs: 162016 blocks:  47504
    refs: 162074 blocks:  47524
    refs: 162132 blocks:  47544
    refs: 162190 blocks:  47564
    refs: 162248 blocks:  47584
    refs: 162306 blocks:  47604
    refs: 162364 blocks:  47624
    

    For me, it's a real memory leak. For the specific case of PR #94336, I don't think that we have to involve the SC or write a PEP. I reviewed the PR. IMO if you make requested changes, the PR can be merged.

  20. kumaraditya303 commented on Jul 3, 2022

    @kumaraditya303
    ContributorAuthor

    IMO if you make requested changes, the PR can be merged.

    Requested changes have been made and also news entry added.

  21. erlend-aasland commented on Jul 15, 2022

    @erlend-aasland
    Contributor

    Kumar, could you please update the PR title and NEWS entry to more accurately describe the change? Apart from that, I'm fine with this.

    Thanks for raising the discussion! 🙂

    (Sorry, this comment was intended for the PR)

  22. kumaraditya303 commented on Jul 15, 2022

    @kumaraditya303
    ContributorAuthor

    Kumar, could you please update the PR title and NEWS entry to more accurately describe the change? Apart from that, I'm fine with this.

    "port multiprocessing static types to heap types" seems fine but I am open to suggestions. Feel free to edit it as you wish :)

    Thanks for raising the discussion! 🙂

    Thanks! :)

  23. added a commit that references this issue on Jul 20, 2022
  24. erlend-aasland commented on Jul 20, 2022

    @erlend-aasland
    Contributor

    Fixed in main with #94336

  25. vstinner commented on Aug 3, 2022

    @vstinner
    Member

    Fixed in main with #94336

    Nice! One less.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions