Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RedocStandalone performance issue on many circular reference #2613

Open
Minh-Trieu opened this issue Oct 29, 2024 · 1 comment
Open

RedocStandalone performance issue on many circular reference #2613

Minh-Trieu opened this issue Oct 29, 2024 · 1 comment

Comments

@Minh-Trieu
Copy link

Minh-Trieu commented Oct 29, 2024

Describe the bug
RedocStandalone have performance issue when rendering a contract with a lot of circular reference. It use a lot of memory (more than 1gb) and can often end to a browser page crash.

Issue faced on [email protected].

Expected behavior
Be able to render the contract with reasonable performance/memory consumption.

Screenshots
Using https://redocly.github.io/redoc/ show the same behaviour
Image

Additional context
Example file that reproduce the behaviour
circular_reference.txt

I also tried to to bundle deferenced with redoc cli but the generated contract was not able to be rendered by RedocStandalone.

@SpeckiJ
Copy link

SpeckiJ commented Nov 15, 2024

I have the same issue with a rather complex and deeply nested schema with many allOfs and have debugged a bit further:

The Memory/CPU usage is caused by the circular-dependency-detection allocating and deallocating massive amounts of strings here:

return stack ? base.concat(stack) : base;

--> concat creates a completely new array and copies all elements over, the old elements are then garbage-collected. In my case this doubles the size of the array each time (it is concatenating itself to itself), and the function is called several hundred thousand times, it very very quickly eats up Gigabytes of memory and the Browser gets overwhelmed with garbage-collection.

this function is called unconditionally once per deref-call:

baseRefsStack = concatRefStacks(baseRefsStack, objRefsStack);

possibly even a second time if the current object is not actually a reference:

refsStack: concatRefStacks(baseRefsStack, objRefsStack),

When commenting out the concat my schema (as well as the one provided above) loads in seconds, compared to crashing the browser after eating all the RAM. There is an ominous MAX_DEREF_DEPTH flag, but it is only checked later in the logic after the stacks have already been concatted, and only in the special case that an actual #ref was present, so it does not work as a protection here and the ref-stack just freely grows to millions of strings.

@RomanHotsiy @AlexVarchuk I would be open to refactor this to be more sane and submit a PR (first proposal would be to use a Set<string> for tracking refs), but I am having trouble understanding whether this whole refsStack-ordeal is really just there for circular dependency detection or if it fulfills another purpose that i cannot see currently?

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

No branches or pull requests

2 participants