Skip to content

Memory Optimizations#5222

Open
rsb-23 wants to merge 3 commits into
psf:mainfrom
rsb-23:main
Open

Memory Optimizations#5222
rsb-23 wants to merge 3 commits into
psf:mainfrom
rsb-23:main

Conversation

@rsb-23

@rsb-23 rsb-23 commented Jul 4, 2026

Copy link
Copy Markdown

Description

Reference : issue #5216

  1. Reduces per-instance memory of Node and Leaf (the two most frequently instantiated objects;
    every token and AST node in a formatted file is one of these)
    and cuts allocation overhead across the hot formatting path.
  2. Removed dead fields (used_names and fixers_applied), never read anywhere.
  3. Simplified unnecessary string and other object creations to reduce memory allocations.
  4. Removed avoidable intermediate allocations in hot paths like r = r0 | r1

Measured on a synthetic benchmark: peak memory 75.325 MB → 20.107 MB after these changes.

Checklist - did you ...

  • Implement any code style changes under the --preview style, following the stability policy?
  • Add an entry in CHANGES.md if necessary?
  • Add / update tests if necessary?
  • Add new / update outdated documentation?

rsb-23 added 2 commits July 5, 2026 03:16
- removed dead fields and redundant vars
- removed unused import
@cobaltt7 cobaltt7 linked an issue Jul 5, 2026 that may be closed by this pull request

@cobaltt7 cobaltt7 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks! Could you add a high-level changelog entry for one or two of the biggest changes?

Comment thread src/blib2to3/pytree.py
Comment on lines -65 to -68
type: int # int: token number (< 256) or symbol number (>= 256)
parent: Optional["Node"] = None # Parent node pointer, or None
children: list[NL] # List of subnodes
was_changed: bool = False

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you migrate these comments into __init__?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added locally, will push soon

Comment thread src/blib2to3/pytree.py
value: str,
context: Context | None = None,
prefix: str | None = None,
fixers_applied: list[Any] = [],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this argument now unused?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, fixer_applied is now unused in both Node and Leaf. But since Node had unused 'context' param, so I kept this param as is.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

diff-shades results comparing this PR (f2c7b3e) to main (d7587ce):

--preview style: no changes

--stable style: no changes


What is this? | Workflow run | diff-shades documentation

@tusharsadhwani

Copy link
Copy Markdown
Collaborator

Did you compare this under the mypyc build? slots shouldn't make that big of a difference after being compiled

@JelleZijlstra JelleZijlstra left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This makes a lot of stylistic changes, many of which are unlikely to affect memory usage.

You claim this reduced memory usage significantly. How did you measure this? Did you compile Black with mypyc? And which specific changes can be proven to help?

Comment thread src/black/brackets.py

priority = priority or self.max_delimiter_priority()
return sum(1 for p in self.delimiters.values() if p == priority)
return sum(p == priority for p in self.delimiters.values())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why would this reduce memory usage? Python won't allocate a new 1 object.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It is mainly a readability/simplicity change, not a memory optimization.

Comment thread src/black/handle_ipynb_magics.py Outdated
Comment thread src/black/handle_ipynb_magics.py Outdated
Comment thread src/black/lines.py Outdated
Comment thread src/black/lines.py Outdated
comments_iter = itertools.chain.from_iterable(self.comments.values())
comments = [str(comment) for comment in comments_iter]
res += "".join(comments)
first, *rest = self.leaves

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The new code overall seems nicer here but note this materializes rest into a new list and therefore might use more memory.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks to point it out.
Since self.leaves is already a list, hence now using it directly instead of creating iter overhead.

Comment thread src/black/output.py
Comment thread src/black/trans.py
group of custom splits.
"""
return (id(string), string)
return id(string), string

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This definitely doesn't affect memory usage.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, its redundant parenthesis hence removed.

Comment thread src/black/trans.py
for start, end in iter_fexpr_spans(fstring):
parts.append(fstring[previous_index:start])
parts.append(fstring[start:end].replace(old_quote, new_quote))
parts.extend((

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

old code is better

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We're unlikely to accept a big change that's just your personal style preferences.

Comment thread src/blib2to3/pgen2/conv.py Outdated
Comment thread src/blib2to3/pytree.py


class Base:
class Base(ABC):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Making this an ABC may well have negative performance effects.

@rsb-23

rsb-23 commented Jul 5, 2026

Copy link
Copy Markdown
Author

@tusharsadhwani @JelleZijlstra
I have used the default build, I will confirm for mypyc.

I took few of the slow testcases to profile for memory and check hot classes.
Here is 1 of the profiler scripts memory_profier.py

- Added comments and Changelog
- reverted additional changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Potential memory optimizations

4 participants