Edit online

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.

This troubleshooting topic addresses scenarios where the server enters a state where it does not respond to client requests or when it responds with a significant delay, usually manifesting with an infinite spinner presented in the browser. Usually, when this happens, server resources are depleted, getting out of memory, exhausting CPU, or exhausting connections. When Oxygen XML Web Author has additional plugins and customizations installed, other than the built-in ones, it is crucial to determine whether the issue is caused by a faulty customization or an actual product bug. This topic provides guidance on identifying the problem and its cause. The target audience of this topic is an integrator who customized the application with custom Java or JavaScript plugins, but it can be followed by anyone who has general knowledge about how Java programs run (e.g. how the memory is allocated).
Note:
As a general consideration, if you manage to reproduce the problem consistently and have identified a concrete set of steps that reproduce the problem, please contact us on Oxygen support team.

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

  1. Open the server logs by following the procedure in How to Locate the Log File and the Log Configuration File.
  2. Check to see if the logs contain java.lang.OutOfMemoryError. If affirmative, an out of memory occurred.

Solution 2 - Check Heap memory using jcmd

  1. Open a terminal that gives access to a JDK inside the machine where the Oxygen XML Web Author server is running:
    1. Find the Java version for the server:
      • If the server was started from the "All Platforms" distribution, simply run java -version.
      • If the server was started from "WAR" distribution, then it depends on the server container that is used, but usually you can run java -version.
      • If the server was started from the "Windows Installer" or "Linux Installer" distributions, open a terminal in the Oxygen XML Editor/jre/bin subdirectory within the installation directory and run java -version.
    2. Download a JDK with the same version as the one the server is running. Note that a different version might also work but it has to be at least the same major version.
    3. Move the JDK on the machine where the server is running.
    4. Open a terminal in the bin directory within the downloaded JDK.
  2. Find the PID of the server by running jps:
    ./JDK/bin>jps -l
    12244 org.apache.catalina.startup.Bootstrap
  3. 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
  4. Identify the total available memory and the used memory. In the above example, it is 75776K total and 22334K used.
  5. 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

  1. For Windows, run:
    ./JDK/bin>jmap -histo 35268 | grep DocumentModel
     num     #instances         #bytes  class name (module)
    -------------------------------------------------------
    1845:             1             48  ro.sync.servlet.ServletDocumentModelCache
  2. For Linux, run:
    ./JDK/bin>jmap -histo <PID> | grep DocumentModel
     num     #instances         #bytes  class name (module)
    -------------------------------------------------------
    1845:             1             48  ro.sync.servlet.ServletDocumentModelCache
  3. 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.
  4. If the number of opened documents is large, consider increasing the memory.

Solution 4 - Inspect what occupies memory by obtaining a Heap Dump

  1. Run jmap to obtain a Heap Dump:
    ./JDK/bin>jmap -dump:live,format=b,file=heap.bin <PID>
    Heap dump file created
  2. 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

To obtain a thread dump, you can either use 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.