Skip to content

Reduce RubyModule/RubyClass size and creation overhead#8617

Merged
headius merged 6 commits intojruby:10-devfrom
headius:reduce_class_size
Feb 11, 2025
Merged

Reduce RubyModule/RubyClass size and creation overhead#8617
headius merged 6 commits intojruby:10-devfrom
headius:reduce_class_size

Conversation

@headius
Copy link
Member

@headius headius commented Feb 9, 2025

We have too much allocation and overhead in the construction logic for RubyModule and all subtypes. This increase overall memory footprint, slows startup, and slows down runtime class creation (especially for singleton objects). This PR will reduce that overhead by:

  • eliminating fields and structures that are no longer necessary,
  • reducing the overhead of remaining fields by initializing them lazily or using more efficient designs,
  • avoid initialization overhead for features that will never be used, like method caches on include/prepend wrappers.

The goal is to have only the minimum overhead and state needed at creation time for each type of "module", so lightweight classes can be created and discarded quickly.

All classes and modules in the system are reachable via the weak
subclasses collections on each class. This reduces overhead of
creating a new module, class or metaclass by avoiding the extra
runtime structures and reduces the overall memory footprint by
N classes * ConcurrentHashMap per-object memory plus WeakReference
memory and overhead.
@headius headius added this to the JRuby 10.0.0.0 milestone Feb 9, 2025
These are only used for one method cache: initialize. This method
is only used for constructing new objects of this class's type, so
this is wasted overhead for everything except concrete classes.

The patch here initializes it lazily since many (most?) RubyModule
subclasses will never need it. We don't bother making it volatile
or atomic since there's no interesting state (occasional double
init will hurt nothing).

Worth pointing out that with indy `new` logic, we may also never
need this cache. The first call may be slow path in indy sites,
but so is the first init of this cache and the first call to use
it. A future commit may remove this altogether.
@headius headius force-pushed the reduce_class_size branch 5 times, most recently from 07d0b75 to 6796bbf Compare February 11, 2025 01:27
Eagerly initializing these adds memory churn to the allocation of
many RubyModule types that will never even access these fields.
Instead we lazily initialize them using an atomic update.
@headius headius force-pushed the reduce_class_size branch 2 times, most recently from cfe5b3a to fd326ce Compare February 11, 2025 01:49
Hardly any RubyModule instances will ever use these fields, so
punt them into a separate data object.
@headius
Copy link
Member Author

headius commented Feb 11, 2025

@kares @enebo If you get a chance to look this over I would appreciate it, but I'm going to move forward and merge. Biggest area I want more eyes on is the lazy volatile inits and the refinementStore object.

@headius headius marked this pull request as ready for review February 11, 2025 02:10
@headius headius merged commit 20a91d0 into jruby:10-dev Feb 11, 2025
52 of 72 checks passed
@headius headius deleted the reduce_class_size branch February 11, 2025 02:10
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.

1 participant