Skip to content

Conversation

@kylixs
Copy link
Member

@kylixs kylixs commented Sep 3, 2025

Problem

The CLASS_LOADER_TYPE_CACHE in SWDescriptionStrategy uses a two-level cache structure with ClassLoader.hashCode() as the first-level key and type
name as the second-level key. In scenarios involving rule engines like Drools that dynamically generate large numbers of classes, this cache grows
indefinitely and causes OutOfMemoryError during long-running applications.

Original Discussion, apache/skywalking#12627

Root Cause

  1. No cache cleanup mechanism: The cache retains entries permanently, even after ClassLoaders are garbage collected
  2. HashCode collision risk: Different ClassLoaders may have the same hashCode, causing cache conflicts
  3. Memory leak: Dynamic classes are typically used once but their cache entries persist forever

Solution

Replace the hashCode-based cache with a WeakHashMap that automatically cleans up entries when ClassLoaders are garbage collected:

  // Before: Memory leak prone
  private static final Map<Integer, Map<String, TypeCache>> CLASS_LOADER_TYPE_CACHE = new ConcurrentHashMap<>();

  // After: Automatic cleanup
  private static final Map<ClassLoader, Map<String, TypeCache>> CLASS_LOADER_TYPE_CACHE =
      Collections.synchronizedMap(new WeakHashMap<>());

Key Changes

  1. WeakHashMap Implementation: Automatically removes cache entries when ClassLoader is GC'd
  2. Direct ClassLoader Reference: Use ClassLoader object as key instead of hashCode to avoid collisions
  3. Bootstrap ClassLoader Handling: Separate cache for null ClassLoader since WeakHashMap doesn't support null keys
  • If this pull request closes/resolves/fixes an existing issue, replace the issue number. Closes #.
  • Update the CHANGES log.

Replace hashCode-based cache with WeakHashMap to automatically cleanup
dynamic class caches when ClassLoader is garbage collected.

- Change CLASS_LOADER_TYPE_CACHE from Map<Integer, ...> to Map<ClassLoader, ...>
- Use Collections.synchronizedMap(new WeakHashMap<>()) for automatic cleanup
- Add separate BOOTSTRAP_TYPE_CACHE for null ClassLoader handling
- Add comprehensive unit tests validating cache behavior

Fixes OOM issues in rule engine scenarios like Drools where dynamic classes
are frequently created and ClassLoaders are recycled.
@wu-sheng wu-sheng requested a review from Copilot September 3, 2025 15:55
@wu-sheng wu-sheng added this to the 9.6.0 milestone Sep 3, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes an OutOfMemoryError issue in the SWDescriptionStrategy cache by replacing a hashCode-based cache with WeakHashMap for automatic cleanup when ClassLoaders are garbage collected. This addresses memory leaks in scenarios involving dynamic class generation like Drools rule engines.

  • Replaces HashMap with WeakHashMap to automatically clean up cache entries when ClassLoaders are GC'd
  • Adds separate handling for bootstrap ClassLoader since WeakHashMap doesn't support null keys
  • Includes comprehensive test coverage for the new cache behavior

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
SWDescriptionStrategy.java Implements WeakHashMap-based cache and bootstrap ClassLoader handling
SWDescriptionStrategyCacheTest.java Adds test coverage for WeakHashMap cleanup, bootstrap handling, and concurrent access

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@wu-sheng
Copy link
Member

wu-sheng commented Sep 3, 2025

@gaojingyuan001 @hyhyf This one.

…builder/SWDescriptionStrategyCacheTest.java

Co-authored-by: Copilot <[email protected]>
GongDewei and others added 2 commits September 4, 2025 09:06
- Convert all Chinese comments to English for better international collaboration
- Maintain original functionality and test logic
- Improve code readability for global contributors
@wu-sheng
Copy link
Member

wu-sheng commented Sep 8, 2025

@gaojingyuan001 @hyhyf Any of you tried this one? This PR was raised due to your use cases.

@wu-sheng
Copy link
Member

@kylixs As this is an enhancement and it seems no harm to the whole system, could you update the changes and we consider to merge this if there is no further feedback?

@wu-sheng wu-sheng changed the title Fix CLASS_LOADER_TYPE_CACHE OOM issue with WeakHashMap (fix #12627) Fix CLASS_LOADER_TYPE_CACHE OOM issue with WeakHashMap Sep 10, 2025
@Ax1an
Copy link
Member

Ax1an commented Sep 15, 2025

After applying this update for a week, the service using Drools no longer experienced memory leaks. I think it can be merged. @wu-sheng @kylixs

@wu-sheng
Copy link
Member

After applying this update for a week, the service using Drools no longer experienced memory leaks. I think it can be merged. @wu-sheng @kylixs

Thanks for the feedback.

@kylixs waiting for you to update change logs.

@kylixs
Copy link
Member Author

kylixs commented Sep 15, 2025

After applying this update for a week, the service using Drools no longer experienced memory leaks. I think it can be merged. @wu-sheng @kylixs

Thanks for the feedback.

@kylixs waiting for you to update change logs.

done

@wu-sheng wu-sheng merged commit 762d31f into apache:main Sep 15, 2025
196 of 199 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants