Project

Profile

Help

Bug #4226

closed

High memory usage when stylesheet aborts with exception

Added by Stewart Witchalls almost 5 years ago. Updated almost 5 years ago.

Status:
Resolved
Priority:
Normal
Assignee:
-
Category:
Performance
Sprint/Milestone:
-
Start date:
2019-05-24
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
Fix Committed on Branch:
Fixed in Maintenance Release:
Platforms:

Description

We're in the process of upgrading (license purchase with legal / purchasing) ... but in the mean time we have to keep using 9.1.0.8

If our app runs the same 2 or 3 transforms over and over (eg. constant stream of 30 requests run in parallel), memory usage is as expected. GC kicks in regularly and the app keeps running at a constant thru put.

If (however) we make one of the stylesheets error with an exception (eg. pass an illegal input into the normalize-string() function), we see Eden grow to the point where the app enters "thrash" and performance degrades to becoming unusable.

The app caches Templates (guava cache) and runs each transform via a new Transformer created using Templates#newTransformer()

If we clear the cache (deleting all Templates and forcing the app to reload + cache them), the Eden space clears down and the process repeats (aka. Eden starts growing to the point where the app stops).

Are the 9.1.08 transformers doing something in their unhappy path that would consume memory?

If yes, is there a way to manually clear memory in my app without discarding the cached Templates?

I'm not asking for a fix, just a workaround.

I can provide graphs showing memory usage and code snippets if required.

Stewart

Actions #1

Updated by Michael Kay almost 5 years ago

We can't give you very much help unless the problem can be reproduced on a more recent software release.

I would suggest taking a heap dump and analyzing it to see which Saxon objects are accounting for the memory usage, and what references to these objects account for them not being garbage-collected. This may give us some clue what is going on.

Actions #2

Updated by Stewart Witchalls almost 5 years ago

Thanks Michael.

Fully understand. 9.1.0.8 is very old.

But ... is there anything I can do to manually clear down thread-local data or the Transformer itself? It only occurs when transformers abort with exceptions.

Actions #3

Updated by Michael Kay almost 5 years ago

Ah yes, I remember now, we did have problems with ThreadLocal caches in the past. I'm sorry, I really can't roll back to remind myself exactly what those problems were and how they were resolved. You need to move forward!

Bugs #1124 and #1481 look relevant.

Actions #4

Updated by Michael Kay almost 5 years ago

  • Status changed from New to Closed

Closing this as unresolved; it appears to be a design issue that was fixed some years ago in more recent Saxon releases, and we have no intention of retrofitting the changes.

If this is not correct and it is still a current issue that can be demonstrated with a repro, then please feel free to re-open it.

Actions #5

Updated by Stewart Witchalls almost 5 years ago

Thanks Michael.

We found the issue. We'd added a custom ErrorListener to javax.xml.transform.TransformerFactory for recording and display stylesheet compilation failures. The TransformerFactory javadoc implies the errorListener is only used by the factory. However, Saxon 9.1.0.8 adds our ErrorListener to the Templates and then the Transformer. As such, our ErrorListener recorded all Transformer runtime exceptions. Since the Templates are cached, we ended up preserving all Saxon generated exceptions until we ran out of memory.

Is the TransformerFactory javadoc correct?

Is this a 9.1.08 bug?

Actions #6

Updated by Michael Kay almost 5 years ago

  • Status changed from Closed to In Progress

Yes, I remember coming across this before. Sometimes these issues with JAXP are because the specification is vague, and sometimes they arise because the specification has been "clarified" over the years to add an interpretation that differs from the interpretation that we took when we first implemented it. I'm not sure which is the case here, but certainly the clause in JAXP TransformerFactory.setErrorListener() that says the error listener is used only for compile time errors and not for run-time errors has been there a long time, and we should probably come into line; though only at a major release, I think, because the change will break some applications.

Related to this is that specifying the ErrorListener at the factory level makes it unsafe to do multiple compilations in parallel. This is one reason why we introduced the XsltCompiler object in the s9api interface, it enables different compilations to be configured independently. Since we now implement the JAXP interfaces as a layer on top of s9api, it becomes easier to impose JAXP restrictions without restricting the s9api interface at the same time.

Actions #7

Updated by Michael Kay almost 5 years ago

I have raised bug #4232 to include this and a whole raft of other known issues affecting the ErrorListener interface.

Actions #8

Updated by Michael Kay almost 5 years ago

  • Status changed from In Progress to Resolved

I transferred bug #4232 to the internal Saxon development project, as I decided the changes were to extensive and disruptive to implement on the 9.9 branch; for the development branch, the handling of error callbacks has been thoroughly redesigned.

Although it's a non-conformance with JAXP that the ErrorListener supplied to a TransformerFactory is used for run-time as well as compile-time errors, I decided not to fix this on the 9.9 branch as the change could break existing applications. Instead, I would advise explicitly setting a different ErrorListener on the Transformer object.

Marking this resolved; but please re-open if there is new evidence.

Please register to edit this issue

Also available in: Atom PDF