Document Loading Freezes or Interaction Failures
Problem
When attempting to open a document, the browser freezes with the loading widget spinning indefinitely, or it may take an excessively long time to open.
Prerequisite
You must have SSH access to the machine where the Oxygen XML Web Author server is running.
Cause 1 - Server runs out of memory
The server exhausts the available RAM memory, leaving it unable to respond to upcoming
requests. When a Java process runs out of Heap memory, the garbage collector runs
intensively to free each piece of memory that can be freed, and the code usually
encounters java.lang.OutOfMemoryError
exceptions for various calls.
Solution 1 - Check if an out of memory error is reported in server logs
- Open the server logs by following the procedure in How to Locate the Log File and the Log Configuration File.
-
Check to see if the logs contain
java.lang.OutOfMemoryError
. If affirmative, an out of memory occurred.
Solution 2 - Check Heap memory using jcmd
-
Open a terminal that gives access to a JDK inside the machine where the Oxygen XML Web Author server is running:
-
Find the PID of the server by running
jps
:./JDK/bin>jps -l 12244 org.apache.catalina.startup.Bootstrap
-
Run
jcmd
:./oxygen-xml-web-author>jcmd <PID> GC.heap_info 35268: garbage-first heap total 75776K, used 22334K [0x0000000740000000, 0x0000000800000000) region size 1024K, 4 young (4096K), 0 survivors (0K) Metaspace used 45037K, capacity 46179K, committed 46336K, reserved 1089536K class space used 5048K, capacity 5564K, committed 5632K, reserved 1048576K
- Identify the total available memory and the used memory. In the above example, it is 75776K total and 22334K used.
- Check to see if the used memory is equal to or almost equal to the available memory. If affirmative, it is probably an ongoing out of memory issue.
Solution 3 - Check how many documents are opened using jmap
-
For Windows, run:
./JDK/bin>jmap -histo 35268 | grep DocumentModel num #instances #bytes class name (module) ------------------------------------------------------- 1845: 1 48 ro.sync.servlet.ServletDocumentModelCache
-
For Linux, run:
./JDK/bin>jmap -histo <PID> | grep DocumentModel num #instances #bytes class name (module) ------------------------------------------------------- 1845: 1 48 ro.sync.servlet.ServletDocumentModelCache
- Considering that an average DITA file consumes about 10MB of RAM, you can multiply the number of documents by 10MB to find an estimation of the memory that the documents occupy.
- If the number of opened documents is large, consider increasing the memory.
Solution 4 - Inspect what occupies memory by obtaining a Heap Dump
-
Run
jmap
to obtain a Heap Dump:./JDK/bin>jmap -dump:live,format=b,file=heap.bin <PID> Heap dump file created
- Open the generated heap.bin file in a tool that can analyze Java Heap Dumps and check if the memory is occupied by objects from a custom plugin or customization.
Solution 5 - Increase memory
If you concluded that the problem was caused by a justified lack of memory, increase the memory by following the instructions from: Increasing the Memory Allocated to Oxygen XML Web Author.
Cause 2 - Server runs out of CPU
In some cases, the slowness of the server is caused by the exhaustion of the CPU by a large number of threads.
Solution 1 - Inspect the threads
Inspect the threads by looking for their name and their stack-trace to identify if they are initiated from custom plugins. If affirmative, continue troubleshooting the plugin's code.
Solution 2 - Obtain a thread dump
pkill -3
<PID>
that outputs the dump to server logs or use
jstack
:./oxygen-xml-web-author>jstack <PID>
2024-10-25 15:36:06
Full thread dump OpenJDK 64-Bit Server VM (11.0.2+9 mixed mode):
Threads class SMR info:
_java_thread_list=0x0000023dc40e74d0, length=47, elements={
0x0000023da0a9f000, 0x0000023dc27a4800, 0x0000023dc27d0800, 0x0000023dc2832000,
0x0000023dc2833000, 0x0000023dc2834000, 0x0000023dc27e6000, 0x0000023dc2837000,
0x0000023dc29a0000, 0x0000023dc2a2e800, 0x0000023dc2d08000, 0x0000023dc3520800,
0x0000023dc5c41000, 0x0000023dc38da800, 0x0000023dc3e1b000, 0x0000023dc3da4000,
0x0000023dc3da4800, 0x0000023dc3f33800, 0x0000023dc41e9800, 0x0000023dc41ec000,
0x0000023dc41e6800, 0x0000023dc41ed000, 0x0000023dc41e7800, 0x0000023dc58eb000,
0x0000023dc58f0800, 0x0000023dc58ee000, 0x0000023dc58ef800, 0x0000023dc58ec800,
0x0000023dc58ed000, 0x0000023dc58ef000, 0x0000023dc58f1800, 0x0000023dc58eb800,
0x0000023dc58f2000, 0x0000023dc58f5800, 0x0000023dc58f6000, 0x0000023dc58f7000,
0x0000023dc58f3000, 0x0000023dc58f4000, 0x0000023dc58f8000, 0x0000023dc58f9800,
0x0000023dc58f8800, 0x0000023dc58f4800, 0x0000023dc3361000, 0x0000023dc3360800,
0x0000023dc3367800, 0x0000023dc3362800, 0x0000023dc3363800
}
"main" #1 prio=5 os_prio=0 cpu=10687.50ms elapsed=568.65s tid=0x0000023da0a9f000 nid=0x32bc runnable [0x0000006be67fe000]
java.lang.Thread.State: RUNNABLE
at java.net.PlainSocketImpl.accept0(java.base@11.0.2/Native Method)
at java.net.PlainSocketImpl.socketAccept(java.base@11.0.2/PlainSocketImpl.java:159)
at java.net.AbstractPlainSocketImpl.accept(java.base@11.0.2/AbstractPlainSocketImpl.java:458)
at java.net.ServerSocket.implAccept(java.base@11.0.2/ServerSocket.java:551)
at java.net.ServerSocket.accept(java.base@11.0.2/ServerSocket.java:519)
at org.apache.catalina.core.StandardServer.await(StandardServer.java:565)
at org.apache.catalina.startup.Catalina.await(Catalina.java:825)
at org.apache.catalina.startup.Catalina.start(Catalina.java:773)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.2/Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.2/NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.2/DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(java.base@11.0.2/Method.java:566)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)
"Reference Handler" #2 daemon prio=10 os_prio=2 cpu=0.00ms elapsed=568.62s tid=0x0000023dc27a4800 nid=0x9284 waiting on condition [0x0000006be6efe000]
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@11.0.2/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@11.0.2/Reference.java:241)
at java.lang.ref.Reference$ReferenceHandler.run(java.base@11.0.2/Reference.java:213)
Cause 3 - Server runs out of connections
The server has a limited number of connections to receive incoming requests. The default limit for requests when Oxygen XML Web Author is started inside Tomcat is 200.
When all connections are occupied, the server is not able to respond to client requests.
Solution 1 - Inspect available connections
The number of available connections can be found using the web-author-monitoring-plugin that logs some metrics to the standard output periodically and you can look for the "webauthor-http_conn_pool_available" metric that shows the available connections.
There are also a few related metrics that may help:
- webauthor-http_conn_pool_pending - The number of pending connections.
- webauthor-http_conn_pool_leased - The number of occupied connections.
- webauthor-http_conn_pool_max - The maximum number of accepted connections.
Solution 2 - Inspecting connections
Each connection is kept open by a thread, so to find the number of open connections,
simply count how many threads have the name like http-nio-8080-exec-10
,
where the trailing number varies.
If it is confirmed that all server connections are exhausted, inspect the threads that hold connections open, look in their stack-trace and check if the thread is opened from a custom plugin. If the connections are kept open by threads started from custom plugins, continue troubleshooting the problem in the plugin's code.