Audience: support and field engineers
Applies to: DualShield v9+ on JDK 25, installed as a Windows service via procrun
...
Before anything: confirm the bundled runtime supports JFR
DualShield ships a JRE, not a JDK, at C:\Program Files\Deepnet DualShield\jre. It has no jcmd, jmap, jstack or jhsdb. If that runtime was also trimmed of the jdk.jfr module then flight recording is unavailable and this page does not apply as written.
Check first:
| Code Block |
|---|
"C:\Program Files\Deepnet DualShield\jre\bin\java" --list-modules | findstr jfr |
"C:\Program Files\Deepnet DualShield\jre\bin\java" --list-modules | findstr jfr
...
Step 1 — create the JFR repository directory
Everything below writes into Tomcat's existing log directory, C:\Program Files\Deepnet DualShield\tomcat\logs, which DAS already writes to and the service account can already write to. Only the JFR repository subdirectory needs creating:
| Code Block |
|---|
mkdir "C:\Program Files\Deepnet DualShield\tomcat\logs\jfr" |
mkdir "C:\Program Files\Deepnet DualShield\tomcat\logs\jfr"
The rolling JFR chunk files are kept in that subdirectory to avoid burying the Tomcat and DAS logs in them. The GC log and the shutdown recording are written to the log directory itself, on purpose — see Downloading through DAC.
Step 2 — validate the options before touching the service
Do this first. A malformed option makes the JVM refuse to start, and diagnosing that through a Windows service is far more painful than through a command prompt.
From a command prompt, using the same JDK the service runs (jre\bin under the install directory). Every option containing a space must be quoted here, and the quotes go around the whole option, not just the path:ava
| Code Block |
|---|
java "-XX:FlightRecorderOptions=repository=C:\Program Files\Deepnet DualShield\tomcat\logs\jfr" "-XX:StartFlightRecording=name=das,settings=default,disk=true,maxage=24h,maxsize=1g,dumponexit=true,filename=C:\Program Files\Deepnet DualShield\tomcat\logs\das-exit.jfr" "-Xlog:gc*,safepoint:file=C:\Program Files\Deepnet DualShield\tomcat\logs\gc.log:time,uptime,level:filecount=10,filesize=20m" -XX:+HeapDumpOnOutOfMemoryError "-XX:HeapDumpPath=C:\Program Files\Deepnet DualShield\tomcat\logs" -version |
Expected: expected the version banner prints, along with a line reporting that recording das DualShield started.
Common failures at this step:
...
Step 3 — add the options to the service
Preferred — the procrun GUI:
1. Run DualShieldwLaunch elevated command prompt and run tomcat*w.exe //ES//<service-name> DualShield from the DualShield tomcat\bin directory. (where * is the version number of Tomcat)
2. Open the Java tab.
3. Append each option below to Java Options, one per line. Do not disturb the existing lines.
Alternative — the registry. DualShield's JVM arguments live in the 32-bit registry view, not the native key:
HKLM\SOFTWARE\Wow6432Node\Apache Software Foundation\Procrun 2.0\<service-name>\Parameters\Java
Edit the Options value (type REG_MULTI_SZ, one option per line). On newer procrun builds running under JDK 9+, an Options9 value may be present and take precedence — if both exist, add the lines to whichever one is already populated with the current settings.
The options to add:
| Code Block |
|---|
-XX:FlightRecorderOptions=repository=C:\Program Files\Deepnet DualShield\tomcat\logs\jfr -XX:StartFlightRecording=name=das,settings=default,disk=true,maxage=24h,maxsize=1g,dumponexit=true,filename=C:\Program Files\Deepnet DualShield\tomcat\logs\das-exit.jfr -Xlog:gc*,safepoint:file=C:\Program Files\Deepnet DualShield\tomcat\logs\gc.log:time,uptime,level:filecount=10,filesize=20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Program Files\Deepnet DualShield\tomcat\logs |
-XX:FlightRecorderOptions=repository=C:\Program Files\Deepnet DualShield\tomcat\logs\jfr -XX:StartFlightRecording=name=das,settings=default,disk=true,maxage=24h,maxsize=1g,dumponexit=true,filename=C:\Program Files\Deepnet DualShield\tomca
Add these unquoted, exactly as shown. Procrun stores each option as its own line and passes it to the JVM whole, so the spaces in the install path need no quoting — and adding quotes here would make them part of the path. Quoting is only needed on a command line or in a .bat or setenv script, as in Step 2.
...
Step 5 — verify it is running
There is no jcmd in the bundled JRE, so verification is by observation:
1. tomcat\logs\gc.log exists and is growing.
2. tomcat\logs\jfr\ contains one or more .jfr chunk files within a minute or two of startup.
3. The JFR startup message appears in the service's stdout log — normally tomcat\logs\commons-daemon*.log or tomcat\logs\stdout*.log, depending on how procrun is configured. A failure to start the recording is reported in the same place.
If tomcat\logs\jfr\ stays empty, check that the directory from Step 1 was created and that the service account can write to it. If the service now fails to start at all, an option is malformed — revert Step 3 and repeat Step 2.
Overhead
Published and commonly-measured figures. These are not measured against DualShield; treat them as guidance, and measure on a representative load test if a customer needs a committed number.
- JFR with settings=default — Oracle states under 1%; field measurements typically 0.5–1%.
- GC logging — negligible, under 0.5%. The cost is buffered file writes of a few KB/s.
- Heap dump on OOM — exactly zero until it fires. When it fires it pauses the JVM for roughly the time needed to write the live heap, on an OutOfMemoryError that was already unrecoverable.
...
Results:
Here is a plain-English breakdown of the results you will see once continuous JVM diagnostics are running on your DualShield server:
A continuous record of what the server was doing right up until a crash or freeze. Instead of losing all clues when a high-CPU incident forces a restart, the Java Flight Recorder (JFR) keeps a rolling 24-hour history of execution samples, memory garbage collection, locks, and I/O saved directly to your hard drive.
Exact identification of the code causing high CPU. By opening the recording files (jfr) in JDK Mission Control, you can drill down into the method profiling to pinpoint the exact internal method or loop that was burning up your CPU resources during an incident.
Immediate separation of memory issues from performance bottlenecks. The separate garbage collection log (
gc.log) lets you look at trends within seconds to easily distinguish whether a slowdown is a genuine hot loop or a garbage-collection death spiral.Automatic snapshots if the server runs out of memory. If the service ever throws an
OutOfMemoryError, the JVM will automatically capture and dump the entire live heap to disk the exact moment it happens, letting you inspect what filled up the memory.Easy retrieval through the console. Because the key summary and exit files are written straight into the main Tomcat log directory, you can download them directly through the DualShield Administration Console (DAC) system log list without needing RDP or file share access.
- You can view OutOfMememory errors under C:\Program Files\Deepnet DualShield\tomcat\logs\. remeberm, these files are only created when system runs out of memory
Collecting after an incident
Ask the customer for the Tomcat log folder, zipped — the same folder they already send for any other DualShield issue:
C:\Program Files\Deepnet DualShield\tomcat\logs{color}
Exclude *.hprof from that zip. A heap dump is as large as the live heap and will make the archive unsendable. Ask for it separately, and only if the case is an OutOfMemoryError.
This works after a restart or reboot. JFR writes chunks to the repository continuously, so the last 24 hours survive a hard kill. das-exit.jfr is additionally written on a clean shutdown.
Open the .jfr files in JDK Mission Control. Start with Method Profiling for a hot loop, and the GC log or the Garbage Collections page for a collection death spiral.
Capturing during the incident, without jcmd
The bundled JRE has no jcmd, jstack or jmap, so the usual on-demand commands are not available on a customer machine. What is available:
- Thread dump — use the product. The CPU Load Monitor task in DAC writes a full thread dump plus per-thread CPU times from inside the JVM, using ThreadMXBean. It needs no external tool. Run it on demand from the task list, or leave it enabled on a schedule. Output goes to the configured export directory (dual/export/directory), not to tomcat\logs.
- JFR — rely on the continuous recording. No dump command is needed. The chunks in tomcat\logs\jfr\ already contain the incident, and das-exit.jfr is written on clean shutdown.
...
- jcmd must run as the same account as the DualShield service. That is usually LocalSystem, so an ordinary elevated prompt will not attach — run it as SYSTEM, for example with PsExec -s.
- The JDK's major version should match the bundled runtime.
...
Downloading through DAC
Because these files land in Tomcat's log directory, DAC's system log file list picks them up, so support can retrieve them through the console without RDP or file share access. The listing is non-recursive and files-only, which is why gc.log, das-exit.jfr and incident.jfr are written to the log directory itself rather than into the jfr subdirectory — the rolling chunk files in jfr\ are not listed and still need collecting by hand.
Viewing log files requires the SystemFile:view permission.
Rolling back
Remove the five options from the service configuration and restart. Nothing else is left behind. Existing .jfr and gc.log files can be deleted freely once a case is closed.
Notes
...
- .

