The safest way to optimize Tomcat on Ubuntu is to measure the bottleneck first, then change one class of settings at a time. Track throughput, p95 and p99 latency, errors, CPU, heap occupancy, garbage-collection pauses, active and queued requests, connections, and database or API saturation before and after every change.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
Ubuntu’s packaged tomcat10, a tarball installation, and a containerized deployment use different paths and service controls. Confirm which installation you have, size the JVM for the measured live set rather than a fixed percentage of RAM, and tune connector concurrency only when the workload and downstream systems can support it.
As an Amazon Associate I earn from qualifying purchases.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsStart with a measurable baseline
Optimization is a comparison exercise, not a hunt for a magic server.xml value. Record a representative traffic window under normal load and, if relevant, a controlled peak test. Keep the request mix, application version, Java version, hardware, proxy settings, and database state constant while testing.
| Metric | What to record | What it tells you |
|---|---|---|
| Request rate | Requests per second, separated by important endpoints | Whether a change increases useful work rather than merely queueing more requests |
| Latency | p50, p95, and p99, plus the slowest important transactions | Whether tail latency improves; averages can hide queueing and pauses |
| Errors | HTTP 4xx/5xx, timeouts, rejected connections, and application exceptions | Whether higher throughput is being purchased with failures |
| CPU | Tomcat process and host utilization, ideally by core | Whether the bottleneck is computation, contention, or waiting |
| Heap and GC | Used heap after warm-up, high-water mark, collection frequency, and pause duration | Whether the JVM has headroom or is spending time reclaiming memory |
| Concurrency | Busy request threads, queued requests, and executor utilization | Whether requests are blocked on I/O or simply competing for CPU |
| Connections | Open, keep-alive, and rejected connections | Whether the connector, proxy, or operating-system backlog is limiting intake |
| Downstream services | Database pool usage, query latency, API latency, and saturation signals | Whether Tomcat tuning would only move the bottleneck into another tier |
Keep a change log with the exact setting, timestamp, traffic window, Java and Tomcat versions, and rollback result. A configuration that raises requests per second but worsens p99 latency or database saturation is not an improvement for most production services.
#1 Best Overall
Identify the Ubuntu installation and service layout
On Ubuntu Noble, the packaged tomcat10 service includes the unit file /usr/lib/systemd/system/tomcat10.service, policy and configuration files under /etc/tomcat10, and runtime configuration, logs, and work directories under /var/lib/tomcat10/conf, /var/lib/tomcat10/logs, and /var/lib/tomcat10/work. A tarball installation under a path such as /opt/tomcat has a different layout and may not use the Ubuntu unit at all.
Confirm the actual deployment before editing anything:
Free tools Windows power users keep installed
One-click scans. No signup required.
sudo systemctl status tomcat10
sudo systemctl cat tomcat10
sudo journalctl -u tomcat10 -b
systemctl show tomcat10 -p FragmentPath -p DropInPaths -p Environment
The unit output identifies the executable, any EnvironmentFile, drop-ins, user, working directory, and configuration arguments. Edit the files named by that unit rather than assuming a path from another installation. Keep the service account separate from root; Apache’s Tomcat 10.1 setup guidance states: “For optimal security, the service should be run as a separate user, with reduced permissions.”
Use a safe, reversible tuning workflow
- Capture the baseline. Save the metrics listed above and note the exact package, Java, and Tomcat versions.
- Back up configuration. Copy the environment file identified by the unit, the active XML configuration tree, and any systemd drop-ins to a dated directory owned by an administrator.
- Change one class of settings. For example, change JVM memory first, then test; do not simultaneously alter heap, thread pools, compression, and CPU affinity.
- Validate syntax and startup. Run
sudo systemctl daemon-reloadafter a drop-in change, restart Tomcat, and inspectsystemctl statusandjournalctl -u tomcat10 -bimmediately. - Run a smoke test. Exercise health checks, authentication, representative read and write requests, uploads, scheduled jobs, and any TLS or HTTP/2 path that production uses.
- Compare the same metrics. Keep the change only if the target metric improves without unacceptable errors, tail latency, resource use, or downstream saturation.
- Roll back quickly. Restore the saved environment or XML files, reload systemd when necessary, restart, and confirm that the previous measurements return.
Set JVM memory in CATALINA_OPTS
Why the variable matters
Tomcat starts several Java processes and commands. JAVA_OPTS is applied broadly, including commands used to stop or inspect Tomcat, while CATALINA_OPTS is intended for the JVM that runs the server. Apache’s current RUNNING.txt says: “Do not use JAVA_OPTS to specify memory limits. You do not need much memory for a small process that is used to stop Tomcat. Those settings belong to CATALINA_OPTS.” Put -Xms and -Xmx in the package-supported CATALINA_OPTS mechanism.
Find the supported package mechanism
Read the unit and its referenced environment file first. If the package uses an environment file, edit the existing CATALINA_OPTS value there and preserve flags already supplied by Ubuntu. If you need an isolated override, use a systemd drop-in:
sudo systemctl edit tomcat10
Add a [Service] section and an Environment assignment containing your complete, merged CATALINA_OPTS value. The following is only a syntax example; the heap numbers are not universal recommendations:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
[Service]
Environment='CATALINA_OPTS=-Xms1g -Xmx2g'
After saving, run:
sudo systemctl daemon-reload
sudo systemctl restart tomcat10
systemctl show tomcat10 -p Environment
ps -o pid,args -C java
If a drop-in replaces an existing assignment, include the existing operational flags in the new value. Verify the running command line rather than assuming that a file edit was consumed.
Choose -Xms and -Xmx from observations
Size the heap from the application’s observed live set, garbage-collection behavior, and the memory limit of the VM, container, or systemd scope. Leave headroom for metaspace, thread stacks, direct and other native buffers, loaded libraries, the page cache, and the operating system. A host with 8 GB of RAM does not have 8 GB available for -Xmx.
- Warm the application with normal traffic and capture used-heap and post-GC occupancy.
- Observe a complete business cycle, including scheduled jobs, large reports, uploads, caches, and traffic spikes.
- Set
-Xmxabove the measured live set by a margin that prevents constant collection, while keeping total process and host memory within the actual limit. - Set
-Xmsaccording to startup behavior and available memory. A large initial heap can reduce resizing but can also starve other services. - Restart and verify heap flags with the Java command line or, when a JDK is installed, tools such as
jcmd <pid> VM.flagsandjcmd <pid> GC.heap_info.
More heap is not a substitute for fixing a leak or an oversized cache. If occupancy rises continuously after collections, investigate retained objects and application behavior. If the kernel kills Java while the heap appears below -Xmx, check native memory, thread count, container limits, and the system journal.
Tune the HTTP connector and executor by queue behavior
Understand the thread-pool controls
maxThreads limits simultaneous request-processing threads when the connector owns its pool. An associated Tomcat Executor takes precedence over connector-level thread-pool attributes, so changing maxThreads on a connector may have no effect when that connector references an executor.
Recommended Free Tools
| Setting or example | Documented value | How to use it |
|---|---|---|
maxThreads |
Default 200 in the cited Tomcat 8.5/10-era connector reference | Verify the exact installed version; increase only when requests wait on I/O and downstream systems can absorb more concurrent work |
minSpareThreads |
Default 10 | Controls ready capacity; raising it consumes memory and threads without helping a CPU-bound service |
NIO pollerThreadCount |
One per processor, capped at two, by default | Leave the documented default unless profiling shows a connector event-loop problem |
| Sample connector | Port 8080, connectionTimeout 20000 ms, redirectPort 8443 |
These are sample configuration values, not workload targets |
| Sample shared executor | maxThreads 150 and minSpareThreads 4 |
Use as an example of wiring, not as a recommended production pool size |
Decide whether more threads will help
- If CPU is already saturated, adding threads usually increases context switching and contention. Reduce work or scale out instead of raising concurrency.
- If threads are mostly blocked on database or remote API I/O, a larger pool can improve throughput, but only until the downstream pool, rate limit, or service becomes saturated.
- If active threads are low while latency is high, inspect the database, remote calls, locks, disk, and garbage collection before changing Tomcat.
- If the queue grows while CPU is available, confirm that the executor is the pool actually in use and that the application is not blocking on a smaller internal pool.
Use acceptCount, timeouts, and keep-alive deliberately
acceptCount controls the queue for connections that arrive while request threads are busy. Raise it only when short bursts create a measurable queue and the operating-system listen backlog, reverse proxy, and file-descriptor limits are configured to support it. A larger queue can turn an immediate refusal into a long timeout, worsening p99 latency.
Align connectionTimeout and keep-alive behavior with the reverse proxy or load balancer. If the proxy closes an idle connection earlier than Tomcat, clients see avoidable resets; if Tomcat holds thousands of idle connections longer than the proxy, memory and file descriptors are wasted. Test with the same proxy path used by clients, not only with a direct connection to port 8080.
The connector reference documents tcpNoDelay as true by default and notes that it generally improves performance. Do not disable it without a measured reason.
Compression is a CPU-versus-bandwidth trade-off
Compression can reduce bandwidth for text responses, especially across a constrained network, but it consumes CPU and can increase latency for small or already-compressed payloads. Measure response sizes, CPU, and p95/p99 latency before enabling it broadly. Limit compression to suitable text content and exclude formats that are already compressed when your connector and proxy policy allow that distinction.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Example connector wiring
A connector and shared executor must be placed in the active server.xml selected by the service. Escape XML correctly and validate the file after editing:
<Executor name='tomcatThreadPool' maxThreads='150' minSpareThreads='4'/>
<Connector executor='tomcatThreadPool' port='8080' connectionTimeout='20000' redirectPort='8443'/>
The values above reproduce Apache’s sample configuration. They are not a sizing prescription. Change one attribute, restart, and compare the baseline metrics.
Keep XML and features version-aware
Tomcat 10.1.60’s configuration reference describes a schemaless, case-sensitive XML configuration and property substitution from JVM and other supported property sources. An attribute copied from another Tomcat major release may be ignored, rejected, or behave differently. Check the installed version before adding connector, executor, TLS, HTTP/2, or protocol attributes.
For a package installation, useful checks include:
dpkg-query -W tomcat10
sudo systemctl cat tomcat10
sudo -u tomcat catalina.sh version
Use the command that matches the service account and installation path; a tarball may expose catalina.sh somewhere else. Keep a known-good XML copy so a failed parse can be reversed without reconstructing the file.
Rank #4
TLS, HTTP/2, and management exposure
The sample server.xml includes optional TLS and HTTP/2 connectors. Terminate TLS at a trusted reverse proxy when that matches your architecture, or configure Tomcat’s TLS connector with current certificates, protocol settings, and a tested renewal process. Do not expose the shutdown port, manager application, host-manager application, or administrative endpoints to untrusted networks. Performance tuning does not justify weakening those boundaries.
Apply security updates before judging performance
Ubuntu security notice USN-8417-1, published 10 June 2026, lists multiple Tomcat issues, including request-body memory exhaustion and HTTP/2 handling problems, and provides fixed package versions. Update the Ubuntu package and restart Tomcat before comparing resource use:
sudo apt update
apt-cache policy tomcat10
sudo apt install --only-upgrade tomcat10
sudo systemctl restart tomcat10
Record the installed Tomcat and Java versions, run the smoke tests, and compare the same latency, error, heap, and connection metrics. A security update can change resource use or request handling; treat it as a new baseline rather than attributing every difference to a tuning change.
Consider systemd CPU and NUMA placement only after profiling
Ubuntu documents persistent systemd controls including CPUAffinity=, NUMAPolicy=, and NUMAMask=. They can help specialized, latency-sensitive deployments, but they constrain where Tomcat may run. A narrower CPU set can reduce total capacity, and an unsuitable NUMA mask can increase remote-memory access.
- Profile per-core CPU utilization, run-queue pressure, context switching, and memory locality during representative load.
- Apply one placement control in a systemd drop-in, keeping the previous drop-in as a rollback copy.
- Restart and compare p95/p99 latency, throughput, CPU utilization, GC pauses, and downstream timings.
- Remove the restriction if capacity falls or tail latency moves to another tier.
Do not use CPU affinity to conceal an application or database bottleneck. Placement is a final refinement after JVM, connector, and downstream behavior are understood.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Compare candidate configurations consistently
Use a small experiment matrix rather than changing settings opportunistically. For each candidate, run the same workload long enough to include warm-up and normal cache behavior:
Best Value
| Comparison dimension | Acceptance question |
|---|---|
| p95 and p99 latency | Did tail latency improve for the endpoints users care about? |
| Throughput at a fixed error rate | Can the service process more requests without increasing failures? |
| CPU utilization | Is extra capacity real, or is the host now contending? |
| Heap and GC pauses | Did memory headroom improve without longer pauses? |
| Active and queued requests | Did queueing fall, and is the selected executor actually controlling it? |
| Connection count and rejects | Are proxy, connector, backlog, and file-descriptor limits aligned? |
| Database and API saturation | Did Tomcat simply transfer the bottleneck downstream? |
Keep the configuration that improves the target metric without violating error, latency, memory, or downstream limits. There is no universal percentage speed-up for Tomcat on Ubuntu; the result depends on traffic, Java version, hardware, application code, and dependencies.
Troubleshoot common tuning failures
Tomcat fails immediately after an edit
Read the current boot journal first. XML is case-sensitive and schemaless, so a misspelled or unsupported attribute can prevent startup. Restore the last known-good XML, verify the installed Tomcat version, and reintroduce the change only after confirming that the attribute belongs to that version.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →The new heap values do not appear
Check systemctl cat tomcat10 for the active environment file and drop-ins, then inspect systemctl show tomcat10 -p Environment and the running Java command line. A connector or service may be using a different installation, or a later environment assignment may override the value. Ensure the flags are in CATALINA_OPTS, not only in a shell profile unavailable to systemd.
Memory exhaustion continues after raising -Xmx
Distinguish a Java heap exception from a kernel or container out-of-memory kill. Check the service journal, host memory, cgroup limits, native allocations, thread count, direct buffers, metaspace, and retained application objects. Raising the heap can make a kernel kill more likely if total process memory exceeds the real limit.
Latency worsens after increasing maxThreads
Check CPU, run queues, GC pauses, database pool wait time, and remote API latency. More request threads often expose a smaller downstream pool or increase contention on a CPU-bound application. Revert to the prior value and size concurrency to the slowest dependency rather than to the number of client connections.
Connections are refused during short bursts
Measure active threads, the accept queue, proxy limits, operating-system backlog, and file descriptors. Raise acceptCount only when the queue is the limiting factor and the rest of the path is configured to hold it. Otherwise, a larger queue can create long waits without increasing completed work.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Compression increases CPU or tail latency
Compare compressed and uncompressed response sizes by content type. Disable compression for already-compressed media and for responses where bandwidth savings do not offset CPU cost. Apply the narrower policy at the proxy or connector layer that actually handles the response.
A repeatable production checklist
- Identify whether the service is Ubuntu’s
tomcat10package, a tarball, or another deployment. - Capture request, latency, error, CPU, heap, GC, queue, connection, and downstream metrics.
- Back up the active environment, XML files, and systemd drop-ins.
- Place JVM memory limits in
CATALINA_OPTSand size them from observed live-set and total-memory headroom. - Confirm whether a shared executor overrides connector-level thread settings.
- Change
maxThreads,acceptCount, timeouts, keep-alive, and compression only in response to measured behavior. - Verify every XML attribute against the installed Tomcat version.
- Install current Ubuntu security fixes and establish a post-update baseline.
- Use CPU and NUMA placement only after profiling shows a placement problem.
- Retain the configuration that improves the chosen metric without shifting failures or saturation downstream.
The practical rule is simple: make the smallest measured change that removes the current bottleneck, verify it under representative traffic, and keep a tested rollback path.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

