Bug #11326
Reduce memory consumption of FWD clients
100%
Related issues
History
#1 Updated by Alexandru Lungu 4 months ago
This task is about attempting to reduce the memory requirement for FWD clients. Customers are currently staying within 256mb of GUI FWD client and 64mb for appservers. The goal would be to check if this is scalable and how we can reduce this requirement especially for environments with many clients.
One idea to start with is the analysis of the font table memory requirement in FWD client. This is ~60MB and forces the FWD client to require at least 128MB to be viable. In the context of tens/hundreds/thousands of clients, this adds up to lots of GB memory. The question is whether we can share memory in between clients to reduce redundancy (e.g. font table if read-only).
#4 Updated by Teodor Gorghe 4 months ago
Alexandru, for web clients, the Font objects are only being used for getting the FontMetrics.
We can easily reduce the web client memory requirement just by storing these metrics instead.
The main problem on this approach is that the FontMetrics stores a Font reference, which avoids Font instances to be erased by GC.
There is an alternative for this is using fontbox, which is just a pure ttf parser. Extracts the font stats which we need (charsWidth, getHeight and getWidths).
#5 Updated by Alexandru Lungu 4 months ago
We can easily reduce the web client memory requirement just by storing these metrics instead.
This sounds reasonable.
There is an alternative for this is using fontbox, which is just a pure ttf parser. Extracts the font stats which we need (charsWidth, getHeight and getWidths).
I don't this is trivial. There are cases where we measure texts on Java client side in order to provide the right metrics. The size of a text can't be inferred using the metrics of a font. It shall be rendered and measured. There are very specific edge cases like kerning. I am not sure if this is the case ONLY for web-scaled (which is happening for several clients that use GUI).
For a bit of contexts: because of the AA in the browser that can't be disabled, we are sometimes forces to measure the size of a text at client side and send that metric to Web in order to do the scaling. There is also some effort to improve this in #9842. You can look at #9842-21 and #9842-63 (+ whole discussion in #9842). In reality, we need to store only the fonts that use web scaling (as dictated by directory.xml), but otherwise I am not sure if we ever need the fonts. I mean, we need them to be sent to the web client in order to render such texts with the right font, but this doesn't require the Java client to retain them forever.
#6 Updated by Teodor Gorghe 4 months ago
Alexandru Lungu wrote:
We can easily reduce the web client memory requirement just by storing these metrics instead.
This sounds reasonable.
There is an alternative for this is using fontbox, which is just a pure ttf parser. Extracts the font stats which we need (charsWidth, getHeight and getWidths).
I don't this is trivial. There are cases where we measure texts on Java client side in order to provide the right metrics. The size of a text can't be inferred using the metrics of a font. It shall be rendered and measured. There are very specific edge cases like kerning. I am not sure if this is the case ONLY for web-scaled (which is happening for several clients that use GUI).
The problem is not that you need to load the Java AWT Font and render it.
When you render the font, the FontDesignMetrics has a cache mechanism (static map) which keeps your Font instances loaded in memory.
BTW, the Font stores in the Heap memory, just the metadata. The rest of the stuff like font glyphs, are stored in off-heap memory.
I have tried to not use FontDesignMetrics and use pure glyphs, but they are cached like FontDesignMetrics. You can't control the memory.
#7 Updated by Teodor Gorghe 4 months ago
- Assignee set to Teodor Gorghe
- Status changed from New to WIP
#8 Updated by Alexandru Lungu 4 months ago
BTW, there are also two maps (text metrics and font metrics) that are loaded from the server. They contain data extracted from Windows to help FWD compute metrics faster based on Windows metrics. This is basically aids cold times by storing all sizes of static labels, so one can render a screen fast, without computing the metrics for each and one text. We usually need this. In the past, we also relied on JS metrics, but the cold time to get text metrics for each and one label was a performance killer. I think Paula knows the task where we discussed this (regarding font size approximation).
For a bit of context, in performance efforts, we always strive to get better times even for memory expense. Now we have the inverted scenario. So, whatever we want to do here, we need to ensure we don't downgrade performance. If we do, it shouldn't be general or noticeable. I would prefer to have something like:
- shared memory between Java clients
- compressed data structured that are seldomly used.
- offloading data to disk if not needed for a long period of time.
- offload more data in JS: this can be interesting as customer's browser is a bit of a free lunch in terms of memory. Instead of having 256MB of client * 100 clients on the deployment machine, we can rather have 128MV * 100 clients on the deployment and off-load the 128MB extra to each and one customer. Each customer browser may afford extra 128MB, but on the VM we can't afford extra 128MB because this multiplies with number of users.
- Of course, we can't cache things on JS and expect to leverage that cache in Java client as the latency would be a nightmare. But maybe some logic can be transferred to Web so that some structures scopes are bound only to the Web client.
- otherwise, maybe we can offload some information on the server, where we can share in between clients. But again, we need to avoid high latency.
- I have a feeling that text metrics may have lots of redundant data, so maybe we can work on that more.
Also, very important: we need to have the memory consumption predictable. We can't afford having thin clients initially that get fatter over time. Setting the right memory to the VM would be a nightmare without deterministic memory usage from the clients. If there is a chance to reach 200MV with a client, than this is the maximum memory we should intake in our computation. This should be optimized.
#9 Updated by Alexandru Lungu 4 months ago
I have a feeling that text metrics may have lots of redundant data, so maybe we can work on that more.
Using something like a TRIE or PATRICIA tree to store the metrics. This will avoid having lots of duplicated string prefixes.
EDIT: instead of storing:
My Account -> metrics My Account: -> metrics
we can store
My Account -> metrics
-> : -> metrics
this alone will optimize 20 bytes as an example. The longer the text the better.
#10 Updated by Teodor Gorghe 4 months ago
I have completely abandon the idea of Font loading from Web FWD client because it is too tedious to work with Font and FontDesignMetrics.
What I have done right now is to precalculate these metrics from FWD server (leading, ascend, descend, each character width, height) and send them to FWD client. The data transmission between FWD server and client is almost instance. The memory consumption is 256KB per font, but I think this is reasonable.
I am refining the implementation and see how it is working.
Also, since the Font definition is no longer required after calling ws.createFont, we can just change FontDetails.fontDefinition field to null. These font definitions takes about 10MB. Also, there is a map from fontManager, which takes about 25MB which I think I should do about it.
The off-heap memory mostly comes from rendering the images, and it is about 100MB. I will also investigate this.
We can also trim the unused jar files because they are being loaded somehow in memory. I don't know much details about that.
#11 Updated by Alexandru Lungu 4 months ago
each character width
This phrase is a red flag for me. This is something that is not usable in kerning fonts. Characters have different widgets depending on neighbor letters. Is this used only for fixed fonts?
Also, since the Font definition is no longer required after calling ws.createFont, we can just change FontDetails.fontDefinition field to null. These font definitions takes about 10MB. Also, there is a map from fontManager, which takes about 25MB which I think I should do about it.
While it looks like you get a good technical grip on the issue, please take into consideration the efforts done to have pixel-perfect texts. There was a non-trivial effort to achieve this, sometimes using webScaled mode. Any solution dropping this level of accuracy is should be carefully analyzed.
I have a feeling that text metrics may have lots of redundant data, so maybe we can work on that more.
Please take a look on this matter as well. On disk, the text-metrics.xml has 24MB (for a customer, indented XML).
#12 Updated by Teodor Gorghe 4 months ago
Alexandru Lungu wrote:
each character width
This phrase is a red flag for me. This is something that is not usable in kerning fonts. Characters have different widgets depending on neighbor letters. Is this used only for fixed fonts?
This is something to consider.
Alexandru Lungu wrote:
Also, since the Font definition is no longer required after calling ws.createFont, we can just change FontDetails.fontDefinition field to null. These font definitions takes about 10MB. Also, there is a map from fontManager, which takes about 25MB which I think I should do about it.
While it looks like you get a good technical grip on the issue, please take into consideration the efforts done to have pixel-perfect texts. There was a non-trivial effort to achieve this, sometimes using
webScaledmode. Any solution dropping this level of accuracy is should be carefully analyzed.
Alexandru Lungu wrote:
I have a feeling that text metrics may have lots of redundant data, so maybe we can work on that more.
Please take a look on this matter as well. On disk, the text-metrics.xml has 24MB (for a customer, indented XML).
Ok, this is good to know. I will look how these are being currently used.
#13 Updated by Teodor Gorghe 4 months ago
- Related to Feature #5776: reduce memory requirements for the FWD client added
#14 Updated by Teodor Gorghe 3 months ago
I have looked into text-metrics.xml and how it is being used (served as a cache, to provide fast and accurate results for text metrics). The FontDesignMetrics still gets created even if we have 100% coverage.
For the approach #11326-10, storing each character width is a solid idea because most of the Java AWT fonts computes the text width by character width (FontMetrics.stringWidth) as SUM(each char width)).
I don't see any place where the font kerning or any font text attribute is being enabled (which could break this idea).
With this change and with FontDetails.fontDefinition + FontManager optimization, I have managed to squeeze 20 MB of client memory. Heap memory baseline after GC is now 71 MB.
I will start to investigate why the offheap memory is still 101 MB.
#15 Updated by Alexandru Lungu 3 months ago
The FontDesignMetrics still gets created even if we have 100% coverage.
What do you mean by 100% coverage? Mind that text-metics covers only static texts. There may be labels that are rendered using variables (aka dynamically). These should still use on the fly metrics.
most of the Java AWT fonts
Can you list some of these?
This is a relevant blog for serif vs sans-serif vs monospace. What you describe is monospace. In FWD, we describe these as "fixed". We have different formulae for fixed vs non-fixed fonts. The non-fixed fonts (aka serif/sans-serif) are way more common in the applications we converts (MS Sans-Serif, Segoe UI, etc.).
I don't see any place where the font kerning or any font text attribute is being enabled (which could break this idea).
Check https://docs.oracle.com/javase/8/docs/api/java/awt/FontMetrics.html#stringWidth and:
Note that the advance of a String is not necessarily the sum of the advances of its characters.
also https://docs.oracle.com/javase/8/docs/api/java/awt/font/TextAttribute.html#KERNING
The default advances of single characters are not appropriate for some character sequences, for example "To" or "AWAY".
Note how AW has a common horizontal rendering space.
#16 Updated by Teodor Gorghe 3 months ago
Alexandru Lungu wrote:
The FontDesignMetrics still gets created even if we have 100% coverage.
What do you mean by 100% coverage? Mind that text-metics covers only static texts. There may be labels that are rendered using variables (aka dynamically). These should still use on the fly metrics.
Not necessarily the FontDesignMetrics, but at least one Font object is being created when calling createFont.
Alexandru Lungu wrote:
most of the Java AWT fonts
Can you list some of these?
These which does not have the following options when creating/defining the font (according to the JDK 17 source code):
- CHAR_REPLACEMENT, FOREGROUND, BACKGROUND, UNDERLINE, STRIKETHROUGH, STRIKETHROUGH, RUN_DIRECTION, ... KERNING, ...
In FWD, we use only use UNDERLINE, which I need to think about this.
Alexandru Lungu wrote:
This is a relevant blog for serif vs sans-serif vs monospace. What you describe is monospace. In FWD, we describe these as "fixed". We have different formulae for fixed vs non-fixed fonts. The non-fixed fonts (aka serif/sans-serif) are way more common in the applications we converts (MS Sans-Serif, Segoe UI, etc.).
No, what I have discussed is not monospace. The letters do not have the same amount of space.
Alexandru Lungu wrote:
I don't see any place where the font kerning or any font text attribute is being enabled (which could break this idea).
Check https://docs.oracle.com/javase/8/docs/api/java/awt/FontMetrics.html#stringWidth and:
[...]
also https://docs.oracle.com/javase/8/docs/api/java/awt/font/TextAttribute.html#KERNING
[...]
Note how AW has a common horizontal rendering space.
I have looked closely in the JVM 17 implementation, which looks like this: FontDesignMetrics.stringWidth
The case which needs attention is when we have UNDERLINE and non-ascii chars.
#17 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
We can also trim the unused jar files because they are being loaded somehow in memory. I don't know much details about that.
Greg, we can create a gradle task which copies in a lib.client folder only the jar dependencies to run the FWD clients. Otherwise, all jars are 'loaded into memory' when loading a Java class, to find it.
There is Software_Dependencies which we can use as a starting point.
#18 Updated by Alexandru Lungu 3 months ago
- File kerning.png added
No, what I have discussed is not monospace. The letters do not have the same amount of space.
Sorry for the confusion. Indeed, this is not related to monospace. Yet, SUM(each char width) is not correct for most fonts. That is what I was trying to point out.
AVAVAVAVAV AAAAAVVVVV
have different widths. In first case, most of the V overlap the A.

#19 Updated by Alexandru Lungu 3 months ago
PS: the image is generated through Linux Editor with Liberation Sans 48. You can replicate using most of the common Windows fonts (Helvetica, Times New Roman, Segoe, Sans Serif, etc.)
#20 Updated by Constantin Asofiei 3 months ago
- Related to Feature #11362: create separate jars and dependency folder for FWD client added
#21 Updated by Teodor Gorghe 3 months ago
Alexandru Lungu wrote:
No, what I have discussed is not monospace. The letters do not have the same amount of space.
Sorry for the confusion. Indeed, this is not related to monospace. Yet,
SUM(each char width)is not correct for most fonts. That is what I was trying to point out.
AVAVAVAVAVAAAAAVVVVVhave different widths. In first case, most of the V overlap the A.
In FWD, for AWT fonts, we have the KERNING disabled.
After a discussion with Alex, the conclusion is that FWD requires KERNING, but I will do some 4GL experiments. There is no KERNING feature in the 4GL language, but there might be something related to the Windows Fonts and how they are rendered. This is a bug which I have didn't considered.
For reducing the memory consumption, the approach which is the most reliable and it does not kill the performance that much is by storing these fonts in the filesystem and reduce the memory stored in the FontDetails (fontDefinition) and customFontData (I think FS cache is fast).
#22 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
After a discussion with Alex, the conclusion is that FWD requires
KERNING, but I will do some 4GL experiments.
Something else to point: if width(string) is not the same as sum(width(char-of-string)), CARET positioning will break. I can't find the exact example from back when implementing this, but I'm pretty sure in FWD we need exact width of a string.
#23 Updated by Alexandru Lungu 3 months ago
We discussed this in #9842
#24 Updated by Teodor Gorghe 3 months ago
4GL does not kern the fonts (I have checked with default MS Sans Serif), default 4GL font.
I will test with other fonts.
#26 Updated by Alexandru Lungu 3 months ago
Indeed, I can confirm the results. Can you also try with a bigger font (close to 30/40)?
It is weird tho. I am most certain we discussed this in the past for different customers and concluded that kerning is a big deal when comes down to font measurement.
#27 Updated by Alexandru Lungu 3 months ago
Teodor, if we can rely on the fact that OE is never using kerning (maybe hints the Win GDI to not enable it), then we can make our lives easier. That would be great.
AWT already doesn't use it.
What about Web, is kerning automatically enabled on web? Can we disabled it?
#28 Updated by Greg Shah 3 months ago
In FWD, for AWT fonts, we have the
KERNINGdisabled.
After a discussion with Alex, the conclusion is that FWD requiresKERNING, but I will do some 4GL experiments. There is noKERNINGfeature in the 4GL language, but there might be something related to the Windows Fonts and how they are rendered. This is a bug which I have didn't considered.
I'm surprised by this. I don't expect that the 4GL would expose kerning to the developer, but I did expect that the WIN32/GDI32 font support implicitly uses kerning in all of its calculations.
#29 Updated by Teodor Gorghe 3 months ago
- File Screenshot from 2026-04-08 15-33-00.png added
- File Screenshot from 2026-04-08 15-37-13.png added
#30 Updated by Alexandru Lungu 3 months ago
Well, maybe MS Sans Serif doesn't have kerning (most probably it doesn't). Can you also test Segoe UI?
#31 Updated by Teodor Gorghe 3 months ago
- File Screenshot from 2026-04-08 15-40-21.png added
#32 Updated by Alexandru Lungu 3 months ago
Well, considering that Java AWT in FWD doesn't have the kerning mode set, will these be rendered correctly?
#33 Updated by Teodor Gorghe 3 months ago
These are rendered correctly, but I think the problem comes on fill-in/editor, when positioning the CARET. I am testing this right now.
#34 Updated by Teodor Gorghe 3 months ago
We somehow mitigated this case with some workaround. Let me check if enabling the kerning does something and the text selection length wobble gets fixed.
#35 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
I have noticed that Arial font actually uses kerning:
Is this from FWD or 4GL?
#36 Updated by Teodor Gorghe 3 months ago
4GL.
#37 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
4GL.
Please post the test and progress.ini (or the font-table).
#38 Updated by Teodor Gorghe 3 months ago
#39 Updated by Teodor Gorghe 3 months ago
FWD renders this correctly both on WEB and Swing, but the problem comes when computing the metrics. It uses the font without KERNING and the metrics are calculated by the fast path, char by char.
- looked it closely and the Swing client renders the text without
KERNING
#40 Updated by Teodor Gorghe 3 months ago
- File Screenshot from 2026-04-08 17-53-07.png added
- File Screenshot from 2026-04-08 17-51-29.png added
FWD trunk:
FWD trunk with kerning:
The WEB client is OK, but the Swing text metrics were wrong.
Tomorrow, I will start to implement the approach with the shared customFont and fontDefinition. I don't think we can get achieve fast performance while not having the Font instances, but the shared approach should save at least 15MB (of 20 MB).
#41 Updated by Alexandru Lungu 3 months ago
Serban I wonder if in #9842 there is also an instability due to the fact that Swing canvas doesn't account for kerning. In other words, maybe what we though about right metrics for the texts in webscale was still off because the kerning was not used. What if webscale would actually use the Swing metrics but with kerning active. Would that provide a better non-skewed display of the text in general? Webscale is made to avoid AA kicking in, but I think the webscale algorithm is not considering kerning, so the text are rendered with Web kerning, but widened because Java measured the text without it.
Can we have an experiment on top of #9842 with it? I would expect that texts would look better. It isn't related to caret, but rather on the text look and feel.
#42 Updated by Teodor Gorghe 3 months ago
Serban, you can take 11326a and test if you need. The text kerning has been enabled and also I have managed to achieve low memory consumption.
Right now, I am working on fixing the text selection regression on Swing, which was already on web client.
It is a bug in AbstractGuiImpl.drawTextSelection which splits the text in three parts and it draws them individually. This is not right when the kerning is being used.
#43 Updated by Alexandru Lungu 3 months ago
It is a bug in AbstractGuiImpl.drawTextSelection which splits the text in three parts and it draws them individually. This is not right when the kerning is being used.
We had this issue for a long time and we didn't manage to find any proper solution by now. There is a very verbose discussion in #9842 (please read it carefully) about what metrics should be used for substrings.
#44 Updated by Teodor Gorghe 3 months ago
- File Swing Selection Fix.mp4 added
- File Web GUI trunk with webscale.mp4 added
- File Web webscale after fix.mp4 added
- File Web Gui without webcale after selection fix.mp4 added
This is a different issue, but it is very related with the cursor position thing.
I have fixed the Swing selection bug, but it kinda breaks the selection in web version because the webscale text is broken (text appears to be more narrow than then Swing version).
I think I am deviating from the original task and I think I should revert the AWT font kerning and work at this on a separate task.
#45 Updated by Teodor Gorghe 3 months ago
- Reverted AWT font kerning.
I will create a separate task for that because there is more Swing font and JS font calculations to be considered.
The second most effective memory optimization is by reducing the jar files from the classpath (there are lots of jar files from server which are not being used on client side, #11362).
Right now, I will do a last look into the off-heap memory. Also, I am checking if -Xss256k is safe to use.
#46 Updated by Teodor Gorghe 3 months ago
The off-heap memory usage is quite large, more than 64M, even after font optimization.
What I have discovered today is that AppCDS actually helps reducing the metaspace usage (which is about 60-80% of off-heap memory) by sharing the loaded classes in the shared OS memory.
I have replaced ReflectASM with pure Java MethodHandle API and the number of shared classes has increased.
Baseline metaspace: ~64 MB.
Non-shared AppCDS (with ReflectASM): 28.5 MB.
Non-shared AppCDS with ReflectASM removed: 13.54MB.
This means that ~50 MB which are the shared loaded classes, are now shared across the FWD client instances.
#48 Updated by Teodor Gorghe 3 months ago
Prior experiments from #10071 showed that performance with JDK17 Reflection API is the same.
I have done a smoke test and I don't see any noticeable difference.
The reason that I chose MethodHandles over Java Reflection API is because Java Reflection API creates lots of proxies (which they are not gonna get into the archive) until exceeds the inflation threshold.
#49 Updated by Constantin Asofiei 3 months ago
Teodor, where can I see these changes?
#50 Updated by Teodor Gorghe 3 months ago
I will commit here, right now I am working to put the javadocs and the history entries.
#51 Updated by Teodor Gorghe 3 months ago
Committed revision 16512 on task branch 11326a:
- Removed ReflectASM completely. Added some small performance improvements.
#52 Updated by Teodor Gorghe 3 months ago
When the web client JVM state is warn, the code cache will get to about 25 MB+, which can't be shared across JVM processes.
AppCDS shares only the class definitions, but if we want to also share the compiled code cache, we need to use JDK 25 Project Layden AOT or the alternative from GraalVM.
#53 Updated by Alexandru Lungu 3 months ago
When the web client JVM state is warn, the code cache will get to about 25 MB+, which can't be shared across JVM processes.
Constantin, I know that you had recent work on #11271 and discussion on #11371. My biggest concern ATM is that the memory demand may spike in certain use-cases (e.g. using redirected terminal). If a report is generated using frames, isn't the report stored entirely in memory (i.e. Fill-Ins representing cells, texts representing labels and so on)? I see that the effort of #11326 is to reduce baseline memory consumption, which is great. But I think we need to also be carefully about potentially large screens / redirected terminals that may create lots of widgets within the client. Also, there are places where we use I/O (e.g. filesystem access, memptr, streams, native invokers, etc.). All of these may require memory spikes. I just want to make sure we also assess these. As long as they are not server-side, then we need to have a second pass through these places and check that everything is buffered / cached / streamed / etc. to not risk bringing big data chunk in memory.
Client is single-threaded, so we need to worry about only one thread doing all this work, but that thread may have several streams opened, memptr handled, and so on, right? How can we assess this?
#54 Updated by Constantin Asofiei 3 months ago
Alexandru Lungu wrote:
Constantin, I know that you had recent work on #11271 and discussion on #11371.
This is only for batch clients. Interactive clients will not be able to use #11371.
My biggest concern ATM is that the memory demand may spike in certain use-cases (e.g. using redirected terminal). If a report is generated using frames, isn't the report stored entirely in memory (i.e. Fill-Ins representing cells, texts representing labels and so on)?
Redirected terminal in FWD is limited to 128x512 lines x cols. So it can't go beyond that. And this is allocated once per terminal.
I see that the effort of #11326 is to reduce baseline memory consumption, which is great. But I think we need to also be carefully about potentially large screens / redirected terminals that may create lots of widgets within the client.
The frame registry can be huge for very complex screens. For interactive clients, we can't let it sit on 64MB, as frames will not be able to fit most likely. But that's on a case by case basis to determine what's the right heap size.
Also, there are places where we use I/O (e.g. filesystem access, memptr, streams, native invokers, etc.). All of these may require memory spikes. I just want to make sure we also assess these. As long as they are not server-side, then we need to have a second pass through these places and check that everything is buffered / cached / streamed / etc. to not risk bringing big data chunk in memory.
See #11327 - that needs to be fixed to not transfer 'in bulk' the memptr content or files, when i.e. COPY-LOB is used.
I'm not sure I understand this. The FWD client can have multiple streams/memptr/etc, where one is used at a time, but:Client is single-threaded, so we need to worry about only one thread doing all this work, but that thread may have several streams opened, memptr handled, and so on, right? How can we assess this?
- for memptr, nothing stays in JVM after the work is done.
- for redirected terminal, multiple streams can be opened at a time
#56 Updated by Teodor Gorghe 3 months ago
Constantin Asofiei wrote:
The frame registry can be huge for very complex screens. For interactive clients, we can't let it sit on 64MB, as frames will not be able to fit most likely. But that's on a case by case basis to determine what's the right heap size.
The frame registry is stored on server side?
Currently, the base heap memory usage is 45 MB (with the VirtualScreenImpl optimization). I will do the experiment with the jar files in a separate directory to see the difference.
Regarding memory spikes, right now, the client seems fine when using 128 MB heap size. I didn't saw any crashes or OutOfMemory issues.
#57 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
Constantin Asofiei wrote:
The frame registry can be huge for very complex screens. For interactive clients, we can't let it sit on 64MB, as frames will not be able to fit most likely. But that's on a case by case basis to determine what's the right heap size.
The frame registry is stored on server side?
UI widgets have parallel structures on both server and client-side. On FWD client, we have WindowManager$WorkArea.windows with all the window and their UI components (the entire UI tree), plus WidgetRegistry class. For example, in customer applications you can open many windows and each one with very complex frames (nested frames, many widgets ,etc). All of this stays in memory on the FWD client.
#58 Updated by Alexandru Lungu 3 months ago
Regarding memory spikes, right now, the client seems fine when using 128 MB heap size. I didn't saw any crashes or OutOfMemory issues.
From #11214, I understood we need to support ~2.7k sessions at once. With 128MB, this means ~350GB to be used, only by heap. Having it in 64MB would halven this to ~170GB which I think is a bit more acceptable. Of course, these is a lot of state and we can't let the client operate in 4MB :) but if we can squeeze it in 64MB, then I think we can be more than happy about it. 128MB is still tricky.
I'm not sure I understand this. The FWD client can have multiple streams/memptr/etc, where one is used at a time, but:
Sorry for my poor phrasing. I meant that the FWD client can have multiple steams/memptr even if single-threaded. Even if you work with a stream at that right time, you can still have some latent streams hanging around in memory. As for the "buts", I did not looked into these yet. It was just my intuition that some things may be memory consuming apart from the actual widgets.
The frame registry can be huge for very complex screens. For interactive clients, we can't let it sit on 64MB, as frames will not be able to fit most likely. But that's on a case by case basis to determine what's the right heap size.
Well, having more windows opened at the same time can lead to multiple complex screens, right? So technically speaking, one user can open 100 windows and break the client.
#59 Updated by Teodor Gorghe 3 months ago
Alexandru Lungu wrote:
Regarding memory spikes, right now, the client seems fine when using 128 MB heap size. I didn't saw any crashes or OutOfMemory issues.
From #11214, I understood we need to support ~2.7k sessions at once. With 128MB, this means ~350GB to be used, only by heap. Having it in 64MB would halven this to ~170GB which I think is a bit more acceptable. Of course, these is a lot of state and we can't let the client operate in 4MB :) but if we can squeeze it in 64MB, then I think we can be more than happy about it. 128MB is still tricky.
128 MB is a safe max memory limit, but I should test what is the maximum window count until the client crashes.
Constantin, about the printer font, I have found it. On Windows 11/10, the default font is Arial with size 11, which is the default printer font.
The Arial font is a Microsoft proprietary font and the most similar font is Liberation Sans.
When using new Font(Font.SANS_SERIF, Font.PLAIN, 11), on linux it will resolve to Liberation Sans and on Windows to Arial. I think this is the most appropriate replacement for FWD.
#60 Updated by Eugenie Lyzenko 3 months ago
Team,
Also please note there is other tasks (#10183, #10286) that has memory usage optimization changes that were rejected from trunk. But I still have no exact answer why. I have no issues with the changes on my local systems.
#61 Updated by Teodor Gorghe 3 months ago
Thanks Eugenie. I will take a look into 10183b spawn.c changes.
I have tried to take the p2j client dependencies only, there were couple of issues while running the appservers clients, which I have fixed. The GUI client works well, but the web client crashes right now and I need to look why.
I have some build.gradle changes which I will put here once I get everything fully working.
Alexandru, your memory consumption estimation is wrong.
We need to also take to account the off-heap memory consumption. Baseline trunk uses 101 MB off-heap memory. I have managed to get it to ~45 MB per client with AppCDS + changes from here. AOT will decrease it to just ~20 MB per client (which also does some heap optimization). The FWD client uses about 6 MB off-heap memory and the rest is just JVM overhead.
The garbage collector also uses a lot of memory. Last time, I saw that GC1 took about 60 MB memory. The best alternative is serial garbage collector, which has almost 0 memory overhead.
#62 Updated by Teodor Gorghe 3 months ago
- File Screenshot from 2026-04-16 09-48-57.png added
- File Screenshot from 2026-04-16 09-55-01.png added
I see a slight memory improvement (10 MB) when using the jar files required only for FWD client.
Appserver heap memory usage has also decreased, from 39 MB to 25 MB.
I have looked into the heap dump and I see that the p2j.jar takes about 637 KB in memory. There is dojo-1.17.3-distribution.zip resource, which takes 1.1M.
I think that the remaining jar resource optimization will lead to just 2 MB less client heap memory.
#63 Updated by Teodor Gorghe 3 months ago
Eugenie, I have looked into 10183b changes, which avoid forking the JVM instance. I don't see anything that can cause spawn issue.
I think the issue comes from a GLIBC version mismatch or Java version. The issue was a long time ago and I don't have the problematic binary which I can check it with ldd.
The changes from 11326a does not depend from 10183b, but it is good to know that there is 50 MB memory per client which is kept by the spawn process.
#64 Updated by Alexandru Lungu 3 months ago
Alexandru, your memory consumption estimation is wrong.
We need to also take to account the off-heap memory consumption
Of course, that is why I wrote "~350GB to be used, only by heap". This is only for the heap metric. There are plenty to be optimized for the customer in discussion - off-heap being one of them. #11214-55 has a view on a production system and how memory is distributed. The point is that #11326 is about the memory consumption of FWD clients, but the server stores a non-trivial state for each of this clients that may skyrocket. Even if the client will work only within 128MB or 64MB, the server-side state may not fit in this limit (session caches, variables, frames, buffers, temp-tables nevertheless).
Even if we optimize the client off-heap memory from 40MB to 30MB (which is good ofc), this will be relatively irrelevant in relation with the server-side state. So we should use this task to reach an acceptable size for the client, so we can change focus to server asap. Doing micro-optimzations will have no benefit considering the server will require hundreds of gb ram to handle these sessions. Also, mind that the OG task (#11215) was running clients with 1gb only heap. having it run in 128mb heap + off-heap is already a huge improvement.
So, having clients run in 64MB heap + 32MB off-heap for example would be enough for this first iteration. The problem will aggressively shift to the server.
#65 Updated by Teodor Gorghe 3 months ago
I have done some measurements and memory consumption for the first client is around 300 MB (server + client). For the next clients, memory consumption per client is 250 MB, with 128 MB heap size.
I am considering to analyze the server-size memory consumption because I have reached to a point where the idle memory usage on client is near optimal.
#66 Updated by Dean Macken 3 months ago
is comment #5742-12 relevant here (is that improvement implemented)?
#67 Updated by Teodor Gorghe 3 months ago
Hi Dean!
Note #5742-12 shows the initial results for font-metrics caching. They are implemented and I can confirm that this is still working on trunk and 11326a.
I can't exactly tell right now every detail because I have focused mostly on the client heap memory usage.
Current optimizations from 11326a are related with what we do with font definition after we send it to the browser through websocket, small optimization when fetching custom fonts. These lowers down the client base heap memory usage from 90 MB to about 60 MB. There is no server side change which increases the memory usage and the performance should be about the same.
There are also some other changes which it will be coming soon on this branch, related with some unexpected Java AWT quirks (eg. linux implementation of new Font("System") and GraphicsEnvironment.getAvailableFontFamilyNames() which loads every installed font from your system and caches them in memory).
Fonts now take about 1 MB in the client heap.
#68 Updated by Dean Macken 3 months ago
Hi Teodor,
wow - great work. really looking forward to getting this all out.
#69 Updated by Eugenie Lyzenko 3 months ago
- File spawn.c
added
Teodor Gorghe wrote:
Eugenie, I have looked into 10183b changes, which avoid forking the JVM instance. I don't see anything that can cause spawn issue.
I think the issue comes from aGLIBCversion mismatch or Java version. The issue was a long time ago and I don't have the problematic binary which I can check it withldd.The changes from 11326a does not depend from 10183b, but it is good to know that there is 50 MB memory per client which is kept by the spawn process.
As far as I know 10183b change did undo for spawn improvements. The 10286a has modified code.
If we want to save ~50MB of RAM per every client session we need it. And it is safe, I used it locally for approx half of the year and have no problems with.
I have attached the improved spawn.c. Do we need this change?
#70 Updated by Eugenie Lyzenko 3 months ago
Eugenie Lyzenko wrote:
Teodor Gorghe wrote:
Eugenie, I have looked into 10183b changes, which avoid forking the JVM instance. I don't see anything that can cause spawn issue.
I think the issue comes from aGLIBCversion mismatch or Java version. The issue was a long time ago and I don't have the problematic binary which I can check it withldd.The changes from 11326a does not depend from 10183b, but it is good to know that there is 50 MB memory per client which is kept by the spawn process.
As far as I know 10183b change did undo for spawn improvements. The
10286ahas modified code.If we want to save ~50MB of RAM per every client session we need it. And it is safe, I used it locally for approx half of the year and have no problems with.
I have attached the improved
spawn.c. Do we need this change?
The only condition to use this fix: the FWD build should be compiled exactly on the same system that is planned as target for deploy. Yes, it is GLIBC/NCURSES compatibility requirement.
#71 Updated by Teodor Gorghe 3 months ago
I have analyzed server-side memory consumption. I have optimized a little bit the FontTable font metrics memory consumption (which can free up to 300-400 MB).
Other than that, there is no anything that can be optimized on server-side.
About Session cache, I have thought for it to be some sort of SoftReference, which will allow GC to reclaim the memory on demand. This idea cannot be applied for every cached DMO because we also store the changes there.
I have also tested JDK 25 AOT, which showed a huge metaspace memory consumption difference (AppCDS shared class definition, but AOT also shared the native code which normally gets compiled on runtime by JIT). Client metaspace is 3M (from 12M).
-XX:+UseCompactObjectHeaders has optimized server heap memory by 28%. However, there is no memory improvement on client side.
#72 Updated by Teodor Gorghe 3 months ago
- Status changed from WIP to Review
- % Done changed from 0 to 100
- reviewer Constantin Asofiei added
- Optimized client side and server side memory.
Constantin, can you take look into the changes?
I think that I have reached to a stage where the memory consumption is minimal.
#73 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
Committed revision 16513 on task branch 11326a:
- Optimized client side and server side memory.
Constantin, can you take look into the changes?
I think that I have reached to a stage where the memory consumption is minimal.
Please rebase first.
#74 Updated by Teodor Gorghe 3 months ago
Rebased 11326a to trunk revision 16525.
#75 Updated by Constantin Asofiei 3 months ago
Teodor, after adding javadoc to the new fields in VirtualScreenImpl, please put it into testing. I don't see any issues.
#76 Updated by Teodor Gorghe 3 months ago
- Status changed from Review to Internal Test
Ok, thanks.
Regarding AppCDS for client processes, do you have any idea how we can optimize archive building process?
What is what I done to make CDS to work on FWD client:- create a lst file, which is the result from the CDS training process. For web clients, I have changed
server/default/webClient/clientConfig/jvmArgsto include-Xshare:off -XX:SharedArchiveFile=fwd-client.lstJVM args. - start FWD server and run a web client session. In that session, try to execute as many scenarios as you can.
- create the jsa archive:
java -Xshare:dump -XX:SharedClassListFile=fwd-client.lst -XX:SharedArchiveFile=fwd-client.jsa -Djava.library.path=... -classpath ... {{jvm_args_from_directory}} com.goldencode.p2j.main.ClientDriver - change
server/default/webClient/clientConfig/jvmArgsto include-Xshare:on -XX:SharedArchiveFile=fwd-client.jsa(removeXshare:off -XX:SharedArchiveFile=fwd-client.lst)
#77 Updated by Constantin Asofiei 3 months ago
- appcds I assume collects only class files loaded by the JVM (from jars, not dynamic)
- is the .jsa file compatible between JVM vendors and versions?
- if is compatible, can we create a 'best of' .jsa file during FWD build, and included it automatically in the FWD Client's JVM args?
#78 Updated by Teodor Gorghe 3 months ago
It collects both classes loaded statically and these loaded dynamically. Class types built dynamically during runtime are not being loaded. I have didn't saw such stuff happen on FWD client.
jsa archives are not compatible between vendors and versions. The lst file is just a plain text file, and contains the classes that needs to be included in the jsa archive. This file also contains internal JVM classes.
Please note that jsa archives depends heavily by the JVM args which you provide. The classpath, GC, etc. needs to be the same.
#79 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
Please note that
jsaarchives depends heavily by the JVM args which you provide. The classpath, GC, etc. needs to be the same.
This part worries me - what happens if these configs are changed? Does it just ignore the .jsa archive? Something else?
#80 Updated by Teodor Gorghe 3 months ago
Constantin Asofiei wrote:
Teodor Gorghe wrote:
Please note that
jsaarchives depends heavily by the JVM args which you provide. The classpath, GC, etc. needs to be the same.This part worries me - what happens if these configs are changed? Does it just ignore the .jsa archive? Something else?
jsa archive load fails and the application fails to start.
#82 Updated by Dean Macken 3 months ago
Hi Greg,
Could we discuss this in this afternoon's meeting?
I think the discussion on sso and lyra will be quick? i'd like to understand the above both in terms of timing and impact.
Also, could we pull it forward 30 mins?
#84 Updated by Greg Shah 3 months ago
- Related to Bug #11327: implement size limited "chunking" for bulk data transfer between client and server added
#85 Updated by Greg Shah 3 months ago
- Related to Feature #6720: lazy hydration added
#86 Updated by Constantin Asofiei 3 months ago
- if 11326a passed testing, this can be merged to trunk (I assume we want this in 9866c, as these are FWD changes)
- provide details of what is needed (in docker script changes terms, directory.xml, etc) so that the lib.client folder (with FWD-client only jar dependencies) is used at runtime when spawning clients, and any other application script changes
- continue working on #11327
- please post an example of a .lst file
- a tool which runs through p2j.jar (selected packages like
p2j/ui,p2j/util), gets the dependencies on some depth level (5-10-20?) from other jars (plus JDK) and creates the .lst file. This can be done via bytecode analysis tools, the Constant Pool has all the info we need to determine static dependencies. - using this .lst file and using the docker configured JVM arguments for the FWD client, we will create the jsa archive
- will automatically inject in directory.xml the settings for appcds, and to any other client launch script, as needed, when enabled at the image build
- also, this must run with Java 17
There is no need to 'warm up' the FWD Client JVM by executing customer scenarios, as this is not using converted code, and even if there are customer app UI widgets, those are small and can stay in the heap (or it can be included as 'additional entry point jar' when building the .lst file to 'share them').
#88 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
Example of
.lstfile.
Thanks, so this can be generated programmatically and not via appcds.
#89 Updated by Teodor Gorghe 3 months ago
- File methods.lst added
This is how a generated .lst file looks like
#90 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
This is how a generated
.lstfile looks like
That is standard JVM method signatures. How having the methods help?
#91 Updated by Teodor Gorghe 3 months ago
These JVM signatures are extracted from dependencies and from p2j bytecode analysis.
We are planing to use static AppCDS, where the archives should also contain stuff from JVM.
There is Dynamic AppCDS, where the archives does not have JVM dependencies, but we can't build these archives from lst.
#92 Updated by Teodor Gorghe 3 months ago
- the are some dependencies which leads to loading the
persistpackage (eg.BrowseGuiImpl->BrowseWidget(referenced from a static constant) ->import static com.goldencode.p2j.persist.P2JQuery.*-> ...), or these which are referenced byErrorManager). I have ended up adding two types of parameters for that bytecode generator: stop class/package (it stops searching when it encounters a class matching this filter) and excluding filter (if it reaches there, don't add the class into the listing file and also scan it). - I got a shared/total loaded classes ratio of 38%, which is a little bit better than the one with
ReflectASM. The ratio is so low because there are lots of lambda functions which are being initialized fromPayloadSerializer(about 40% of non-shared classes), some lambdas from internal JDK implementation of Spring (20%), but there are also some libraries from internal JDK, likexerceswhich is impossible to find it the referenced from bytecode analysis.
#93 Updated by Teodor Gorghe 3 months ago
- we generate a base JVM listing file by just running FWD client without any network parameter:
java -XX:DumpLoadedClassList=jdk_base_classes.lst -cp ../lib.client com.goldencode.p2j.main.ClientDriver
- generate
lstfile from static analysis - merge these two listing file
I have also done some PayloadSerializer changes, which are very important.
With these two combined, I have managed to get the same metaspace consumption as with the jsa from a normal AppCDS pipeline.
#94 Updated by Alexandru Lungu 3 months ago
Teodor, please mind the effort in #9939 to get a fwd-client.jar archive that contains only the client required classes. Thus, any dependency from client to server will be fixed.
#95 Updated by Teodor Gorghe 3 months ago
- File MethodCallAnalyzer.java
added
Where should I put this class?
I should put in FWD, or I should create a separate project?
#96 Updated by Greg Shah 3 months ago
Teodor Gorghe wrote:
Where should I put this class?
I should put in FWD, or I should create a separate project?
Please add std headers and javadoc. It should not have the AGPL license part. So the header would be:
/* ** Module : MethodCallAnalyzer.java ** Abstract : <something_here> ** ** Copyright (c) 2026, Golden Code Development Corporation. ** ALL RIGHTS RESERVED. Use is subject to license terms. ** ** Golden Code Development Corporation ** CONFIDENTIAL ** ** -#- -I- --Date-- -----------------------------Description------------------------------ ** 001 TG ... */
Then you can add it to the project I just created at ~/secure/code/p2j_repo/tools/dev_helpers.
#97 Updated by Greg Shah 3 months ago
There are a range of different ideas discussed in this task, which is pretty confusing to understand status.
Teodor, would you please post the full list of open items to work, organized in 3 categories:
- Low Risk AND Quick to Implement
- Medium Risk OR Low Risk But Takes a Bit More Work
- High Risk OR Bigger Work Needed
This will help us organize the plan for getting these merged.
#98 Updated by Teodor Gorghe 3 months ago
- Changes from below are already in 11326a and were reviewed by Constantin.
- removal of ReflectASM, Jetty SpreadsheetWebApp configuration to avoid searching through entire classpath
- refactored
getCustomFontDatato avoid loading the entire font table on client-side PRINT_FONTfix to avoid loading a font with invalid name, which causes loading 2029 fontsLegacyFontMetricsrework to reduce server-side memory consumptionFontHelper.hasLocalFontfont caching in a temporary file to avoid callinggetAvailableFontFamilyNames(), which loads all your fonts from the systemGuiWebDriveroptimization to reclaim unused memoryVirtualScreenImplrefactorization to improve memory usageWebHtmlBrowserchanges which avoids loading the entiretikadependency in memory
- Client AppCDS integration. I have already done the
.lstbuilding, which has proved good results. What is left to work: integrateMethodCallAnalyzerand lst building into the FWD docker image building process. - Configuring the
lib.clienton the projects which needs memory optimization for FWD client (this is a medium-risk change because I don't know which dependency might be missing, I have already included these which I have made FWD client to start up). PayloadSerializerrefactorization to reduce the number of lambda functions (which fills the metaspace memory). I have already done this, but I need to double check if I have missed something before commiting to a branch.
p2j.jarmodularization (Alexandru is already working on this), does not provide a substantial memory reduction because of #11326-62.
#99 Updated by Teodor Gorghe 3 months ago
Committed revision 1 on ~/secure/code/p2j_repo/tools/dev_helpers:
- Added bytecode project.
#100 Updated by Constantin Asofiei 3 months ago
- run this tool to generate the .lst file
- run the program to generate the archive
- automatically configure the directory.xml clientConfig/jvmArgs to have the arguments to use the appcds archive
Do we want this to be optional (via a flag at the docker image build script)?
Teodor: the tool needs to also specify the .lst file name and path where it will be saved.
#101 Updated by Teodor Gorghe 3 months ago
- PayloadSerializer changes to optimize metaspace memory usage.
#102 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
Committed revision 16531 on task branch 11326a:
- PayloadSerializer changes to optimize metaspace memory usage.
- please fix the formatting (curly braces on their own line, implements/extends on their own line, etc).
PAYLOAD_COREis OK, I mean in the other types. - cache the
cls.getComponentType()andcls.getDeclaredConstructor()types
#103 Updated by Teodor Gorghe 3 months ago
- File Main.java
added
OK, the cls.getDeclaredConstructor() I understand the reasoning why should be cached, but I don't see a reason why I should cache cls.getComponentType().
Total time for non-cached cls.getDeclaredConstructor().newInstance() (ms): 1797 Total time for non-cached cls.getComponentType() (ms): 68 Total time for cached cls.getDeclaredConstructor().newInstance() (ms): 323 Total time for empty loop (ms): 65
#104 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
I don't see a reason why I should cache
cls.getComponentType().[...]
That's a method call, a native call and a field access. We just remove these trips, maybe JVM will JIT-compile this code and be fast, but replacing it with a field avoids these method and native calls.
#106 Updated by Teodor Gorghe 3 months ago
Constantin Asofiei wrote:
Teodor Gorghe wrote:
I don't see a reason why I should cache
cls.getComponentType().[...]
That's a method call, a native call and a field access. We just remove these trips, maybe JVM will JIT-compile this code and be fast, but replacing it with a field avoids these method and native calls.
Ok, the changes are in 11326/r16532.
#107 Updated by Teodor Gorghe 3 months ago
Committed revision 16533 on task branch 11326a:
- Added LstExporter
Uncommitted revision 1 on ~/secure/code/p2j_repo/tools/dev_helpers because I have moved it to 11326a/r16533.
#108 Updated by Constantin Asofiei 3 months ago
LstExporter:
- please fix the 'module' header (now has
com.goldencode.bytecode.LstExporter.java) - there are some lines longer than 110 limit, please fix these
11326a is OK to be in test.
#109 Updated by Teodor Gorghe 3 months ago
Thanks.
I have committed the changes into 11326a/r16534.
#110 Updated by Razvan-Nicolae Chichirau 3 months ago
Smoke-testing a customer app with 11326a passed.
#111 Updated by Teodor Gorghe 3 months ago
ChUI regression testing has passed.
I will continue testing ETF and the remaining customer apps.
#112 Updated by Teodor Gorghe 3 months ago
Regression testing has passed (ETF and two other customer applications).
There was just one regression related with PayloadSerializer, which was fixed in 11326a/16535
#113 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
There was just one regression related with
PayloadSerializer, which was fixed in 11326a/16535
I don't understand what the problem was. Can you detail a little?
#114 Updated by Teodor Gorghe 3 months ago
The problem came from spawn JVM, which tried to load EventDefinition (throws ClassNotFoundException)EventDefinition has RoaringBitmap dependency, which is not available from spawn p2j.jar.
In the previous optimization, I have added cls.getDeclaredConstructor() in Cls constructor, which JVM load the class in memory before providing the Constructor object.new Cls(EventDefinition.class) is called on static initialization of PAYLOAD_CLASSES, which triggered a crash in Message.writeExternal.
I have fixed this issue by moving cls.getDeclaredConstructor() call into Cls.get(), which lazily loads EventDefinition only when we need that.
#115 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
The problem came from spawn JVM, which tried to load
EventDefinition(throwsClassNotFoundException)EventDefinitionhasRoaringBitmapdependency, which is not available from spawn p2j.jar.
In the previous optimization, I have addedcls.getDeclaredConstructor()inClsconstructor, which JVM load the class in memory before providing theConstructorobject.new Cls(EventDefinition.class)is called on static initialization ofPAYLOAD_CLASSES, which triggered a crash inMessage.writeExternal.I have fixed this issue by moving
cls.getDeclaredConstructor()call intoCls.get(), which lazily loadsEventDefinitiononly when we need that.
Please add a comment explaining this, where cls.getDeclaredConstructor() gets called . So it doesn't get changed in the future.
#116 Updated by Teodor Gorghe 3 months ago
I have added the comment.
#117 Updated by Constantin Asofiei 3 months ago
Teodor Gorghe wrote:
I have added the comment.
Thank you. Any other testing required?
#118 Updated by Teodor Gorghe 3 months ago
I don't think (I have also tested with the lib.client).
#119 Updated by Constantin Asofiei 3 months ago
- Status changed from Internal Test to Merge Pending
Please merge 11326a now.
#120 Updated by Teodor Gorghe 3 months ago
- Status changed from Merge Pending to WIP
- % Done changed from 100 to 90
Branch 11326a was merged into trunk as rev. 16557 and archived.
Moved this task to WIP because we need to migrate customer application setup to use lib.client.
#121 Updated by Eugenie Lyzenko 2 months ago
Teodor Gorghe wrote:
Branch 11326a was merged into trunk as rev. 16557 and archived.
Moved this task to WIP because we need to migrate customer application setup to use
lib.client.
Do you mean the current trunk 16557 should not work with big M application? Because it really does not work.
#122 Updated by Constantin Asofiei 2 months ago
Teodor, Eugenie is right; there was a 'typo':
=== modified file 'src/com/goldencode/p2j/main/BaseClientBuilderOptions.java'
--- old/src/com/goldencode/p2j/main/BaseClientBuilderOptions.java 2026-04-20 06:04:16 +0000
+++ new/src/com/goldencode/p2j/main/BaseClientBuilderOptions.java 2026-05-07 17:27:58 +0000
@@ -541,7 +541,7 @@
sb.append(cp);
for (int i = 0; i < jars.length; i++)
{
- String extraJar = libPath + File.pathSeparator + jars[i] + FileExtensions.JAR_POSTFIX;
+ String extraJar = libPath + File.separator + jars[i] + FileExtensions.JAR_POSTFIX;
File jarFile = new File(extraJar);
if (jarFile.exists())
{
#123 Updated by Constantin Asofiei 2 months ago
Teodor Gorghe wrote:
Moved this task to WIP because we need to migrate customer application setup to use
lib.client.
There are also the docker changes to integrate appcds for FWD clients, using Hotel GUI as a demo.
#124 Updated by Constantin Asofiei 2 months ago
Eugenie, please do some smoke-tests with 11326b rev 16559 (has the fix from #11326-123), if is OK I'll merge it ASAP.
#125 Updated by Eugenie Lyzenko 2 months ago
Constantin Asofiei wrote:
Eugenie, please do some smoke-tests with 11326b rev 16559 (has the fix from #11326-123), if is OK I'll merge it ASAP.
OK. I'll checking out this branch now. But this can take a time. The alternative can be if you attach the modified file here and I will test it over recent trunk. This can save a bit of time.
#126 Updated by Constantin Asofiei 2 months ago
The patch is in note #11326-122 that's the only change separator instead of pathSeparator
#127 Updated by Eugenie Lyzenko 2 months ago
Constantin Asofiei wrote:
The patch is in note #11326-122 that's the only change separator instead of pathSeparator
Your fix works fine. All is back again. Please merge into trunk when possible.
#128 Updated by Constantin Asofiei 2 months ago
Branch 11326b was merged to trunk rev 16559 and archived.
#129 Updated by Teodor Gorghe 2 months ago
hotel_gui project up and running from a docker container and I have made some initial changes for client AppCDS integration:
- added
deploy.appcdsant task, which creates the.lstfile usingLstExporter. It also creates a.jsaarchive, which is used for local setups. These files are stored indeploy/client/appcds, which are being included indeployarchive, which can be used for building the docker image later on. - changed the
hotel_guidockerfile to build appcds file.jsa. - changed
directory.xml.templateto use AppCDS archive by default.
I am continuing implementing the lib.client after doing some investigation on #11452.
Also, the runtime JVM args are hardcoded in build.xml. There are important because classpath is important, JSA archive also depends by the type of use garbage collector, etc.
One idea which I have is getting this information from directory.xml.
I have focused building one client JSA archive, using JVM parameters which are compatible between each other, but if multiple JSA files are required, build.properties and the dockerfile needs to be changed.
#130 Updated by Teodor Gorghe 2 months ago
- File client_appcds.patch
added
#131 Updated by Constantin Asofiei 2 months ago
Teodor Gorghe wrote:
One idea which I have is getting this information from
directory.xml.
Yes, we need this. But we need to consider classpath-extra-jars and exactly how FWD builds the classpath and passes it to the spawner.
Also, the directory.xml needs to be prepared to use the appcds config via jvmArgs.
I have focused building one client JSA archive, using JVM parameters which are compatible between each other, but if multiple JSA files are required,
build.propertiesand thedockerfileneeds to be changed.
This is a good point: we can have multiple types of clients spawned via the directory (appserver, GUI, ChUI, batch processes), which have their own classpath or JVM settings. Can we build a tool which gets the directory.xml and does everything for all clients (i.e. walks through all clientConfig nodes and resolves the JVM args and classpath, and automatically adds the appcds config)?
#132 Updated by Teodor Gorghe 2 months ago
Constantin Asofiei wrote:
Teodor Gorghe wrote:
One idea which I have is getting this information from
directory.xml.Yes, we need this. But we need to consider
classpath-extra-jarsand exactly how FWD builds the classpath and passes it to the spawner.Also, the directory.xml needs to be prepared to use the appcds config via jvmArgs.
I have focused building one client JSA archive, using JVM parameters which are compatible between each other, but if multiple JSA files are required,
build.propertiesand thedockerfileneeds to be changed.This is a good point: we can have multiple types of clients spawned via the directory (appserver, GUI, ChUI, batch processes), which have their own classpath or JVM settings. Can we build a tool which gets the directory.xml and does everything for all clients (i.e. walks through all clientConfig nodes and resolves the JVM args and classpath, and automatically adds the appcds config)?
Yes, I can build a simple tool gets the configuration for each type of client.
The directory.xml is already using the JVM args since I have changed directory.xml.template to use AppCDS (./docker/docker_prepare.sh is only required to update to the new configuration)
#134 Updated by Alexandru Lungu 2 months ago
deleted
#135 Updated by Teodor Gorghe 2 months ago
hotel_gui project:
- Created a tool in FWD, called JvmArgsExtractor.java, which extracts the client parameters from directory.xml.
- Modified the changes from #11326-130 to integrate this tool.
- I have changed deploy.appcds ant task and moved most of it into deploy/server/deploy_appcds.sh for flexibility for each project. I have also created a version for powershell, which is in deploy/server/deploy_appcds.ps1. Ant task is still there, which uses these two scripts.
- Added support for classpath_extra_jars and support for libPath on prepare_dir.sh.
The local setup didn't changed that much, the new ant task is a dependency of deploy-prepare task.
For docker setup, I have it working, but there is a problem which I will fix it. /opt/hotel/client/appcds is not persisted like how /opt/hotel/etc and /opt/hotel/logs are. These appcds files does not belong to the docker image because we need the directory.xml, which contains the JVM args.
I think I will move this into etc or create a new volume mapping in host deploy, called appcds, which maps to /opt/hotel/appcds.
#136 Updated by Teodor Gorghe 2 months ago
Constantin, I have done the lib.client change in deploy.prepare task for hotel_gui (which takes from p2j/dist/client, p2j.jar, p2j.dll and libp2j.so).
The tricky part comes for docker, which requires changes for FWD docker image. I am planning to take the dist archive for client and extract into /opt/fwd-deploy/client/lib.
Right now, for everything, we use /opt/fwd-deploy/convert/build/lib for both server/client/convert.
#137 Updated by Teodor Gorghe 2 months ago
- File hotel_gui_11326c.patch
added - Status changed from WIP to Review
- reviewer Roger Borrello added
These are the latest changes to integrate AppCDS.
Also committed revision 16565 to branch 11326c, which adds client dist into FWD docker image.
Constantin, please review 11326c.
Roger, take a look into hotel_gui changes.
Thanks.
#139 Updated by Constantin Asofiei 2 months ago
Teodor, 11326c looks OK.
#140 Updated by Teodor Gorghe 2 months ago
Thanks.
I have found some issues while parsing directory.xml from #11472, and I would need to rethink everything about JvmArgsExtractor.java.
In directory.xml, you can provide a more complex structure like server/<serverID>/clientConfig/jvmArgs, server/<serverID>/<client_type>/.../jvmArgs, server/default/clientConfig/jvmArgs, /server/default/runtime/default/.../jvmArgs, etc.
Currently, it uses XPath for getting the JVM args.
I was thinking to replace the current approach with one which uses the already existing code (eg. load directory.xml using DirectoryService and do the scan using it), which already handles default values. I need to take in consideration about multiple server ids and the precedence rules from Utils.getDirectoryNodeWorker. Maybe I can extend the XPaths.
#141 Updated by Constantin Asofiei 2 months ago
Teodor Gorghe wrote:
I was thinking to replace the current approach with one which uses the already existing code (eg. load
directory.xmlusingDirectoryServiceand do the scan using it), which already handles default values. I need to take in consideration about multiple server ids and the precedence rules fromUtils.getDirectoryNodeWorker. Maybe I can extend the XPaths.
This would be better, but I'm not sure how you create the context for a specific user. Because you can have /server/default/runtime/<user>/clientConfig .
#142 Updated by Teodor Gorghe 2 months ago
- File hotel_gui_11326c.patch
added
Roger, I have forgot to include the docker/repo/entrypoint/docker-entrypoint_prepare.sh.
These changes were included here.
#143 Updated by Teodor Gorghe 2 months ago
- Improved implementation for support of client types.
#144 Updated by Constantin Asofiei 2 months ago
- Status changed from Review to Internal Test
Teodor, the changes look good. Please do some small testing just to double-check normal setup works without appcds enabled.
#145 Updated by Roger Borrello 2 months ago
=== modified file 'docker/docker-compose_create_pg_cluster.yml'
--- old/docker/docker-compose_create_pg_cluster.yml 2026-01-21 23:26:06 +0000
+++ new/docker/docker-compose_create_pg_cluster.yml 2026-05-15 05:24:16 +0000
@@ -1,19 +1,19 @@
services:
hotel_db:
- image: hotel_gui_postgres:latest
+ image: hotel_gui_pg14_server:451_11326c-16563_20260514a
container_name: hotel_db
command: >
bash -c "
cd /tmp &&
- sudo fwd_create_pg_cluster.sh --pgdata /pgdata/fwdcluster --rolefile-path /docker-entrypoint-initdb.d
+ sudo fwd_create_pg_cluster.sh --pgdata ${PGDATA:-/opt/hotel/db/fwdcluster}
"
ports:
- ${PGPORT:-5432}:${PGPORT:-5432}
volumes:
- - hotel_db_postgres:/pgdata:delegated
+ - hotel_db_postgres:/opt/hotel/db:delegated
environment:
- PGDATA: /pgdata/fwdcluster
+ PGDATA: /opt/hotel/db/fwdcluster
PGPORT: ${PGPORT:-5432}
I don't see any need for changes to this compose yaml.
- The latest version of image should be used, and the name of the image comes from
docker/build_docker.sh. Did that change? - The mount points are generic inside the container to the volume, so they don't need to include the application info.
- Please make sure to remove
--rolefile-path /docker-entrypoint-initdb.dfrom the command-line. It's not in your addition.
#147 Updated by Teodor Gorghe 2 months ago
docker/docker-compose_create_pg_cluster.yml changes should be reverted. This was an attempt to create a pg cluster, but I have figured out since then how to use.
Thanks a lot Roger!
After #11326c gets to trunk, I will commit these changes to hotel_gui, after the testing is done.
For directory.xml template files, I will change -Xshare:on to -Xshare:auto to make the clients to start even if there is no valid archive in that directory.
This eliminates a variable when debugging the application.
I think the prepare scripts for Windows they also needs to be changed (I have forgot to include in the patch).
#149 Updated by Constantin Asofiei 2 months ago
- Status changed from Internal Test to Merge Pending
Teodor, please merge 11326c now if you are satisfied with the changes. Also commit the docker-related changes to Hotel GUI.
#150 Updated by Teodor Gorghe 2 months ago
Testing was done on 4 projects, without any issue.
I am merging this now.
#151 Updated by Teodor Gorghe 2 months ago
Branch 11326c was merged into trunk as rev. 16575 and archived.
#152 Updated by Teodor Gorghe 2 months ago
- % Done changed from 90 to 100
Committed the changes into hotel_gui revision 454.
#153 Updated by Teodor Gorghe 2 months ago
- Status changed from Merge Pending to Test
#154 Updated by Roger Borrello 2 months ago
Teodor Gorghe wrote:
Committed the changes into hotel_gui revision 454.
If you want the base 24.04 Docker images to contain this version, you must have the version on xfer updated as well, since that is where it is pulled from. So don't forget to make the request, unless you can do it yourself.
rfb@xfersrv01:~$ update_app.sh +N deploy/server/deploy_appcds.ps1 +N deploy/server/deploy_appcds.sh M* build.xml M* deploy/server/directory.xml.template M* deploy/server/prepare_dir.ps1 M deploy/server/prepare_dir.sh M* docker/docker-compose.yml M* docker/docker-compose_client.yml M docker/docker-compose_prepare.yml M* docker/docker-compose_server.yml M docker/docker_prepare.sh M docker/repo/entrypoint/docker-entrypoint_prepare.sh M* docker/run_docker.ps1 M docker/run_docker.sh M json_template.sh All changes applied successfully. Updated to revision 454 of branch sftp://rfb@devsrv01/opt/secure/code/p2j_repo/samples/hotel_gui
#155 Updated by Teodor Gorghe 2 months ago
Ok, thanks for letting me know!
#156 Updated by Roger Borrello about 2 months ago
Teodor Gorghe wrote:
Committed the changes into hotel_gui revision 454.
I made matching changes in hotel revision 204. Can you review them?
#157 Updated by Roger Borrello about 2 months ago
I know that all the thinning down that Teodor has done for this task is good... I could use some thinning myself! But I'm curious about whether or not the same attention is being paid to the "server" set of jars (files built into the ./dist/server directory) as these (the ./dist/client directory). The docker images that are built for applications leverage the archives, and deploy them according to the Docker image being built. For now, all the images utilized the ./dist/client/convert set of jars, because there were issue running applications with the others. I believe with this task, the ./dist/client set of files is more reliable, and should be used to build runtime Docker images for applications, since we want them to be "thin".
So should the ./dist/client jars be used for server and client images? (Server being the image that starts the server process and has access to the directory.xml) or should the server use the ./dist/server jars?
#158 Updated by Teodor Gorghe about 2 months ago
It is hard to provide an answer. What I know is that the server image spawns FWD client instances (so it should have the client dist files), it should have the server dist files (obvious), but the FWD server also does a conversion during runtime (eg. dynamic queries, dynamic tables, etc), so it should contain the convert dist set. I don't know what is exactly the difference between convert and server, which I think I shall take a look into build.gradle.
I will review the hotel changes tomorrow (it's almost 10 PM on my timezone).
#159 Updated by Teodor Gorghe about 2 months ago
hotel changes.Overall, they seem right, but I have one observation:
build.xml:deploy.preparetask does not contain the part which copies the client jars intolib.client.
There is something which I forgot to include in hotel_gui project, which is the change of including client_lib_path into JSON template files.
Should I do this change as well?
#160 Updated by Teodor Gorghe about 2 months ago
- Status changed from Test to WIP
- Fixed missing dependency issue on SIGNATURE widget.
Constantin, please review, it's a safe change.
#161 Updated by Teodor Gorghe about 2 months ago
- Status changed from WIP to Review
#162 Updated by Constantin Asofiei about 2 months ago
- Status changed from Review to Internal Test
Teodor, the change looks good.
#163 Updated by Teodor Gorghe about 1 month ago
I have tested the SIGNATURE widget, which now it works.
Since there is just one dependency change, introducing bcel on FWD client, which already was on FWD server, I don't think there is anything which needs to be tested since this dependency introduces apache commons lang3, which is already included in the project.
#164 Updated by Radu Apetrii about 1 month ago
Teodor Gorghe wrote:
I have tested the
SIGNATUREwidget, which now it works.
Since there is just one dependency change, introducingbcelon FWD client, which already was on FWD server, I don't think there is anything which needs to be tested since this dependency introduces apache commons lang3, which is already included in the project.
Sooo, is there anything else left to test? May I place this in the merge queue?
#165 Updated by Teodor Gorghe about 1 month ago
I don't see anything else what I can test. This needs full regression testing?
#166 Updated by Radu Apetrii about 1 month ago
Teodor Gorghe wrote:
I don't see anything else what I can test. This needs full regression testing?
Constantin?
#167 Updated by Roger Borrello about 1 month ago
Teodor, have you looked at the build of the FWD Docker containers which are used as the basis for the application Docker images? I had been utilizing the container project, but that is deprecated for the tools/docker/docker_build.sh in FWD (most recent in 9709e branch). The basic premise is that the appropriate versions of dist ZIP files are used to position FWD jars in the /opt/fwd-deploy directories:
# Step 6/11 RUN (pushd /tmp/repo; ./deploy_fwd.sh /opt/fwd-deploy "$DEPLOY_LIST" -f; popd)
An example of the dist directory after including archive in the gradlew command:
-rw-rw---- 1 rfb rfb 23085742 Jun 9 17:42 fwd_deploy-admin_4.0.0_p2j_9709e_16636_20260609.zip -rw-rw---- 1 rfb rfb 93619568 Jun 9 17:42 fwd_deploy-client_4.0.0_p2j_9709e_16636_20260609.zip -rw-rw---- 1 rfb rfb 331107810 Jun 9 17:42 fwd_deploy-convert_4.0.0_p2j_9709e_16636_20260609.zip -rw-rw---- 1 rfb rfb 37625273 Jun 9 17:44 fwd_deploy-docs_4.0.0_p2j_9709e_16636_20260609.zip -rw-rw---- 1 rfb rfb 171682 Jun 9 17:44 fwd_deploy-native_4.0.0_p2j_9709e_16636_20260609.zip -rw-rw---- 1 rfb rfb 311860088 Jun 9 17:44 fwd_deploy-server_4.0.0_p2j_9709e_16636_20260609.zip -rw-rw---- 1 rfb rfb 25237910 Jun 9 17:44 fwd_deploy-spawner_4.0.0_p2j_9709e_16636_20260609.zip
So if you were to use the "convert spawner" options to deploy_fwd.sh you would end up with the below in your docker image:
rfb@fwddev_40_ubuntu_2404_jdk17_9709e_latest_container:~/projects/fwd/9709e$ ls -l /opt total 12 lrwxrwxrwx 1 root root 23 May 14 10:52 fwd -> /opt/fwd-deploy/convert drwxr-xr-x 1 rfb rfb 4096 May 14 10:51 fwd-deploy drwxr-xr-x 2 root root 4096 May 14 10:52 spawner rfb@fwddev_40_ubuntu_2404_jdk17_9709e_latest_container:~/projects/fwd/9709e$ ls -l /opt/fwd-deploy/ total 16 drwxr-xr-x 1 rfb rfb 4096 May 14 10:51 convert drwxr-xr-x 1 rfb rfb 4096 May 14 10:51 spawner rfb@fwddev_40_ubuntu_2404_jdk17_9709e_latest_container:~/projects/fwd/9709e$ ls -l /opt/fwd-deploy/convert/ total 68 drwxr-xr-x 1 rfb rfb 4096 Feb 1 1980 build -rwxr-xr-x 1 rfb rfb 21881 May 14 10:51 import.sh drwxr-xr-x 1 rfb rfb 4096 Feb 1 1980 locale drwxr-xr-x 1 rfb rfb 4096 Feb 1 1980 rules drwxr-xr-x 1 rfb rfb 4096 Feb 1 1980 src drwxr-xr-x 1 rfb rfb 4096 Feb 1 1980 tools -rw-r--r-- 1 rfb rfb 200 May 14 10:51 version.properties
The FWD_LIB environment variable defaults to /opt/fwd in the Docker images, which is a symlink to /opt/fwd-deploy/convert. This makes FWD available for Docker images that come FROM the FWD Docker images. For example, the Hotel GUI Docker files in ./docker:
-rw-rw---- 1 rfb rfb 2945 Apr 8 18:34 fwd_4.0_ubuntu_client_Dockerfile -rw-rw---- 1 rfb rfb 4081 Apr 8 18:38 fwd_4.0_ubuntu_server_Dockerfile -rw-rw---- 1 rfb rfb 4086 Apr 8 18:36 fwd_4.0_ubuntu_pg_server_Dockerfile
are available so that the client Docker file would be able to leverage a FWD Docker image setup for client usage, the server for the FWD Docker image for server usage, and the pg_server as a server with PG server also build into the FWD Docker image.
Is this task to match up with building the proper FWD docker image that would contain the client archive so memory of FWD in that image would be lessened, or is this task making the set of jars dynamic so that use of a FWD client would build the list of jars as needed? I'm wondering if this Dockerfile setup is where building the image so you can symlink to /opt/fwd-deploy/client for the location of the jars is "moot" now.
#168 Updated by Teodor Gorghe about 1 month ago
Roger Borrello wrote:
Is this task to match up with building the proper FWD docker image that would contain the client archive so memory of FWD in that image would be lessened, or is this task making the set of jars dynamic so that use of a FWD client would build the list of jars as needed? I'm wondering if this Dockerfile setup is where building the image so you can symlink to
/opt/fwd-deploy/clientfor the location of the jars is "moot" now.
I have looked at both container FWD docker images (22.04 and 24.04) and the docker file from FWD tools/docker, which is based on Ubuntu 24.04.
AFAIK, container docker file uses ALL for ./deploy_fwd.sh and tools/docker just client convert spawner.
By adding client to the the DEPLOY_LIST will increase the FWD docker image with about 500 MB.
Right now, we use just 1 base FWD docker image for client, server images. For server, right now, we need both client and convert images, due to the nature how FWD works, server needs client images because it spawns clients in the same container.
For client, we can use just have a FWD client base image, to reduce the total size of container/client application image.
The main purpose for this task is to reduce RAM memory usage of FWD clients. It is important because high RAM memory consumption is a huge bottleneck for the converted applications because they can't run more than just a few clients with a medium sized machine. Even if there are just 20-30 MB RAM which are being freed up per client when using AppCDS with client jars, this is worth if you run for example, 40+ clients on a 32GB machine.
#169 Updated by Roger Borrello about 1 month ago
Currently there is no distinguishing between Docker images that are including various levels of PostGreSQL client, so I've had to add that to the image name. So fwd_4.0_ubuntu_24.04_jdk17 might have included PG14, PG15, PG16, or PG17. So I had to add that information to the name... but that name now collides with the fwd_4.0_ubuntu_24.04_pgNN_jdk17 name that was indicative of the server image. This means I have to update the naming convention to either include client in the client image, so fwd_4.0_ubuntu_24.04_client_pgNN_jdk17 would indicate a FWD client image with the PGNN client installed. The trickle-down effect is that any scripts would need updating to indicate the correct name, although there aren't that many that are specifically utilizing client images, so that is a minimal impact.
#170 Updated by Roger Borrello about 1 month ago
Teodor, #9709-971 contains some info related to the FWD docker images. The Hotel apps, as well as any customer apps, would probably be relying upon the new client images that are built by the tools/docker/docker_build.sh process. I will probably replace the container projects build_fwd_24.04.sh script with this one, since it is more complete.
#171 Updated by Teodor Gorghe about 1 month ago
All the project build scripts may need to be modified to use this smaller docker image.
#172 Updated by Radu Apetrii about 1 month ago
Radu Apetrii wrote:
Teodor Gorghe wrote:
I don't see anything else what I can test. This needs full regression testing?
Constantin?
I would like to revive this note. Alex/Constantin: do you think there is any more testing required for 11326d?
#173 Updated by Constantin Asofiei about 1 month ago
- Status changed from Internal Test to Merge Pending
Radu Apetrii wrote:
Radu Apetrii wrote:
Teodor Gorghe wrote:
I don't see anything else what I can test. This needs full regression testing?
Constantin?
I would like to revive this note. Alex/Constantin: do you think there is any more testing required for 11326d?
11326d can be merged now.
#174 Updated by Teodor Gorghe about 1 month ago
- Status changed from Merge Pending to Test
Branch 11326d was merged into trunk as rev. 16606 and archived.
#175 Updated by Roger Borrello about 1 month ago
Teodor, where do you envision deploy_appcds.sh to be invoked (besides build.xml)? Should this be done at server startup? Or is this purely a build-time thing? We can't utilize build.xml in circumstances, like Docker image build.
#176 Updated by Teodor Gorghe about 1 month ago
ant deploy.appcds for local setup or docker prepare in case of docker environments.
Should be invoked everytime when there is a jvm arg change or a change on a jar file.
#177 Updated by Roger Borrello about 1 month ago
- File appcds_mem.sh
added - File getcp.sh
added - File deploy_appcds.sh
added - File client.sh
added
I had some challenges getting the AppCDS setup going for hotel... see #11472-24 and 25.
There were some updated Claude helped me accomplish, mostly in the area of properly setting up the classpath before running deploy_appcds.sh so that the exact collection of libraries could be stored off in a <type>.cpath file, and then reused at the client load point. I'm not sure if this is correct, but it got me going.
When I got it running, I also got Claude to help me come up with a way to compare before/after. The --no-appcds option was added to client.sh to allow for running with/without AppCDS in use, and the appcds_mem.sh uses measurements for memory.
I am reworking this now that I understand the classpath comes from p2j.jar manifest.
#178 Updated by Teodor Gorghe about 1 month ago
There is no support for client.sh AppCDS yet. Top priority was web clients, appservers and batch-process.
#179 Updated by Roger Borrello about 1 month ago
Teodor Gorghe wrote:
There is no support for
client.shAppCDS yet. Top priority was web clients, appservers and batch-process.
client.sh is a major method for launching batch processes.
#180 Updated by Teodor Gorghe about 1 month ago
I have thought that they were being launcher by ClientSpawner, my bad.
#181 Updated by Roger Borrello about 1 month ago
Claude is trying to convince me that the LstExporter isn't necessary, and rather the manifest of the p2j.jar should be utilized. Here is a report.
AppCDS Client Memory & Startup Findings¶
Comparison of the FWD ChUI client launched with AppCDS versus without it, plus the rework that made AppCDS a net win for both the command-line client and the server-spawned webClient.
Measured with deploy/client/appcds_mem.sh (command-line client) and deploy/client/appcds_mem_pid.sh (snapshot an already-running webClient by PID). Both sample /proc/<pid>/smaps_rollup and confirm via /proc/<pid>/maps whether the .jsa is actually mapped.
Outcome¶
After the rework, the appcds configuration is faster to start and lighter, and its per-client advantage grows as clients are added:
| Scenario | appcds PeakRSS | no-appcds PeakRSS | appcds ToSettle | no-appcds ToSettle |
|---|---|---|---|---|
| 1 client | 177.9 MB | 186.6 MB | 1.9s | 2.5s |
| 5 clients | 799.1 MB | 875.0 MB | 3.9s | 5.3s |
The appcds peak RSS fell from 270 MB (bloated archive) to 178 MB once the class list was trimmed -- see "The journey" below.
Setup¶
- Launcher:
client-terminal.sh(ChUI entry point) - appcds: default
client.sh-- classpath<libPath>/p2j.jar(whose manifestClass-Pathpulls in the curatedclient/libset) +-XX:SharedArchiveFile=.../default.jsa - no-appcds:
client.sh --no-appcds-- full FWD discovery classpath (~361 jars), no archive (a stable baseline; its config never changed across runs, so small run-to-run differences are measurement noise) - Memory in MB;
ToSettle= wall-time to the last RSS increase (startup/warmup proxy);ARCHIVE= whether the.jsais mapped.
The journey: bloated -> lean¶
Before -- explicit classpath + static class list (bloated)¶
The archive was dumped against an explicit ~169-entry classpath and a class list that concatenated LstExporter static reachability with the runtime dump:
| Source | Classes |
|---|---|
base_lst -- LstExporter static reachability over the full classpath |
18,039 |
runtime_lst -- -XX:DumpLoadedClassList, real client startup |
2,007 |
| Total | 20,053 |
Resulting default.jsa: 144 MB. Measurements:
| Mode | Clients | PeakRSS | Pss | PrivDirty | Archive |
|---|---|---|---|---|---|
| appcds | 1 | 274.2 | 255.8 | 227.3 | mapped |
| no-appcds | 1 | 184.9 | 161.3 | 150.5 | absent |
| appcds | 5 | 1343.3 | 1124.0 | 1088.8 | mapped |
| no-appcds | 5 | 953.8 | 818.5 | 800.3 | absent |
Root cause of the loss: a ChUI client actually loads ~2,000 classes, but the archive held ~20,000. A static CDS archive eagerly loads its archived app-loader classes during VM init, so appcds materialized ~18k extra classes' runtime metadata as committed PrivDirty (~+57 MB/client) that the lazily-loading no-appcds run never created. Cross-process sharing helped (SharedClean rose with client count) but could not offset the eager-load bloat.
After -- manifest classpath + runtime-only class list (lean)¶
The archive is now dumped against <libPath>/p2j.jar (letting the jar manifest expand the classpath) and the class list is the runtime dump only (~2,007 classes). Measurements:
| Mode | Clients | PeakRSS | Rss | Pss | SharedCln | PrivClean | PrivDirty | Archive | ToSettle |
|---|---|---|---|---|---|---|---|---|---|
| appcds | 1 | 177.9 | 177.9 | 158.2 | 27.7 | 0.7 | 149.6 | mapped | 1.9s |
| no-appcds | 1 | 186.6 | 186.6 | 167.7 | 26.0 | 0.9 | 159.7 | absent | 2.5s |
| appcds | 5 | 799.1 | 791.7 | 668.2 | 140.7 | 0.0 | 651.0 | mapped | 3.9s |
| no-appcds | 5 | 875.0 | 863.6 | 745.0 | 134.7 | 0.0 | 728.9 | absent | 5.3s |
Per-client scaling (the cross-process sharing payoff)¶
| Pss per client | K=1 | K=5 |
|---|---|---|
| appcds | 158.2 | 133.6 |
| no-appcds | 167.7 | 149.0 |
| appcds advantage | ~9.5 MB | ~15.4 MB |
appcds's per-client footprint drops faster as clients are added (158->134, -25) than no-appcds (168->149, -19), because the lean archive's pages are shared across the JVMs (SharedClean up, PrivClean ~0). That is the benefit AppCDS is designed for, now compounding the single-client win instead of being buried under eager-load bloat.
The fix in deploy_appcds.sh¶
- Dump against the manifest classpath.
client_cpis thedirectory.xmlvalue<libPath>/p2j.jar.p2j.jar'sMANIFEST.MFClass-Pathentry lists every sibling jar, so this single entry IS the full client classpath -- and it is the exact form the server hands the spawned webClient. Dumping against this form is what lets BOTH client types map one archive (see webClient note). - Runtime-only class list by default. The list is the
-XX:DumpLoadedClassListoutput (~2,007 classes), not the static walk. .lstSPI sanitize.LstExportercopiedMETA-INF/services/*entries verbatim, including legal inline comments (e.g. ecj'sjavax.tools.JavaCompiler:org.eclipse.jdt...EclipseCompiler #Eclipse compiler). The-Xshare:dumpclass-list parser rejects a class name with a trailing comment, so asedstrips inline#...while leaving full-line comments intact.
Why INCLUDE_STATIC exists (and defaults to off)¶
There are two ways to build the class list, with a real trade-off:
- runtime_lst (
-XX:DumpLoadedClassList) -- exactly the classes one real client startup loads (~2,007). Tight and low-memory, but only covers the code paths exercised during that capture. Application screens/features not hit during the dump are simply not in the archive (they still load fine at runtime, just without the CDS speedup). - base_lst (
LstExporterstatic reachability) -- every class transitively reachable from the client roots across the whole classpath (~18,039). Broad coverage that catches classes a single idle startup never touches, but it is wildly over-inclusive on a fat classpath.
The static set is what caused the 144 MB / +57 MB-per-client bloat above (eager loading of archived classes at VM init). So the choice was:
- delete
LstExporter-> lose the broad-coverage option entirely, or - leave it on -> ship the bloat by default, or
- make it opt-in -> keep both behaviors available.
INCLUDE_STATIC takes the third path. Default false gives the lean, runtime-only archive -- the configuration that produced the measured win above. Setting INCLUDE_STATIC=true re-adds the static set for cases where maximal startup coverage is worth the memory cost (e.g. you want features not exercised during the dump pre-archived too, ideally after driving real screens during the DumpLoadedClassList step).
Implementation note: under the manifest classpath (-cp p2j.jar), LstExporter cannot see the manifest-referenced jars (java.class.path lists only p2j.jar), so when enabled the INCLUDE_STATIC branch builds an explicit analysis classpath from the lib dir's jars -- separate from the (manifest) dump classpath.
INCLUDE_STATIC trade-off (measured)¶
The lean-default decision was confirmed with real numbers on both client types.
webClient (single client, snapshot by PID):
| Archive | PeakRSS | PrivClean | PrivDirty | Archive |
|---|---|---|---|---|
| lean (default) | 265.5 | 4.7 | 237.8 | mapped |
static (INCLUDE_STATIC=true) |
374.3 | 22.9 | 328.4 | mapped |
The static archive costs ~+109 MB on the webClient -- higher PrivClean (more archived pages read in) and PrivDirty (more eagerly-loaded class metadata).
Command-line client, 5 concurrent clients:
| Metric | lean appcds | static appcds | no-appcds |
|---|---|---|---|
| PeakRSS | 799.1 | 1262.6 | 925.7 |
| Pss | 668.2 | 1069.4 | 773.2 |
| PrivDirty | 651.0 | 1034.3 | 755.1 |
| SharedCln | 140.7 | 217.5 | 134.6 |
| ToSettle | 3.9s | 4.7s | 7.0s |
With the static archive, command-line appcds is ~+296 MB (~+59 MB/client) over no-appcds -- back to a memory loss. The only thing static improves over lean is startup (4.7s vs 3.9s, ~0.8s), and that is a poor exchange for ~+74 MB/client: lean already captures the bulk of the startup win (3.9s vs ~7s for no-appcds) while staying under no-appcds on memory.
Conclusion: lean (runtime-only) is the right default for both client types. Use INCLUDE_STATIC=true only when startup latency is paramount and RAM is abundant. (ToSettle varies with system load while many clients launch, so trust within-run deltas more than across-run ones; the memory columns are steadier.)
Why this also fixes the webClient¶
The webClient is spawned by the server; getcp.sh/.cpath never apply to it. The server builds its command from directory.xml clientConfig, and BaseClientBuilderOptions.addJarsToClasspath() defaults the classpath to <libPath>/p2j.jar. Confirmed from a live webClient command line:
java -Xshare:auto -XX:SharedArchiveFile=../appcds/client/default.jsa -Xmx128m \
-Djava.library.path=/opt/fwd-deploy/client/lib \
-classpath /opt/fwd-deploy/client/lib/p2j.jar \
com.goldencode.p2j.main.ClientDriver ...
So the webClient runs -cp p2j.jar (manifest-expanded) -- never an explicit list. Previously the archive was dumped against the explicit ~169-entry classpath, so the webClient's classpath did not match and -Xshare:auto silently skipped the archive (verified: no .jsa in /proc/<pid>/maps). Dumping against <libPath>/p2j.jar now matches the webClient automatically -- no directory.xml classpath injection needed.
How to reproduce¶
- Re-dump:
cd deploy/server && ./deploy_appcds.sh /opt/fwd-deploy/client/lib/p2j.jar(setINCLUDE_STATIC=truefirst only if you want the broad static archive). - Command-line client:
cd deploy/client && ./appcds_mem.sh -- -i 1and./appcds_mem.sh --clients 5 -- -i 1. - webClient: start server, open
https://localhost:8443/chui, find the PID (pgrep -fa com.goldencode.p2j.main.ClientDriver), then./appcds_mem_pid.sh --reset appcds <pid>; reconfigure/bounce for the baseline and./appcds_mem_pid.sh no-appcds <newpid>.
Caveats¶
- Part of the absolute memory gap is the curated ~167-jar classpath vs the full ~361-jar
no-appcdsdiscovery, not purely the archive. The pure-CDS contribution is clearest inToSettleand in the growing per-clientSharedClean/Pssadvantage. - The command-line client now runs the same thin classpath as the webClient (
p2j.jar+ manifest, nohotel.jar/fwdspi.jar); it ran fine (STATUS=ok). If a deployment needs the app jars client-side, append them after.cpathingetcp.sh --appcds(CDS only requires the dump classpath to be a prefix).
#182 Updated by Teodor Gorghe about 1 month ago
I think that deploy_appcds.sh LstExporter class/package list can be fine-tuned even further to find a good balance between archive size and percentage of shared class.
Pure AppCDS generates about 4k classes and I think I can target to achieve this value.
I think there is something wrong on your setup. How the LstExporter has generated lst with 20k classes? When I have implemented this, I have tested it and it was around 8k classes (archive size was ~50-60 MB).
#183 Updated by Roger Borrello about 1 month ago
- File client.sh
added - File deploy_appcds.sh
added - File appcds_mem_pid.sh
added - File appcds_mem.sh
added - File prepare_dir.sh
added - File directory.xml.template added
Teodor Gorghe wrote:
I think that
deploy_appcds.shLstExporterclass/package list can be fine-tuned even further to find a good balance between archive size and percentage of shared class.Pure AppCDS generates about 4k classes and I think I can target to achieve this value.
I think there is something wrong on your setup. How the
LstExporterhas generated lst with 20k classes? When I have implemented this, I have tested it and it was around 8k classes (archive size was ~50-60 MB).
I ran INCLUDE_STATIC=true ./deploy_appcds.sh /opt/fwd-deploy/client/lib/p2j.jar, and there are 167 jars in there. The breakdown of classes is:
| classes | package | what it is |
|---|---|---|
| 4,324 | org/apache/* | batik, axis2, poi, tika, commons… |
| 3,684 | com/goldencode | FWD itself |
| 2,310 | org/eclipse | ecj — the Eclipse Java compiler |
| 1,913 | net/sf | jasperreports |
| 1,062 | com/fasterxml | jackson |
| 851 | com/google | guava / gwt |
| 713 | org/junit | JUnit (a test framework!) |
| 668 | com/ctc | woodstox |
| 454 | org/jfree | jfreechart |
| 338 | com/lowagie | openpdf |
| 288 | org/jsoup | jsoup |
- We analyzed the entire client deployment (167 jars), which bundles reporting (jasper, jfreechart, openpdf, poi), the ecj compiler, JUnit, jackson, SOAP (axis2/axiom), tika, jsoup, etc. LstExporter only adds a referenced class if its bytes are present on the classpath — so the more jars present, the deeper the transitive walk resolves. Their ~8k almost certainly came from a leaner analysis classpath where many of those references hit "Cannot find" and never expanded.
LstExporterseeds from every META-INF/services/ file across all jars (loadJarAndSPIs adds each SPI provider as a root). With 167 jars, that's a lot of unrelated roots — ecj's javax.tools.JavaCompiler, JUnit's engines, Jasper, Jackson — each then walked transitively. That SPI seeding is the multiplier that turns a fat classpath into 20k. (org/eclipse 2,310 and org/junit 713 showing up at all is the smoking gun — a client archive should never pull in a compiler or a test framework.)
Claude can be pretty dramatic. I hope I'm giving you good feedback. I did get useful tools in appcds_mem_pid.sh which I can pass the spawned webclient PID, and it adds to the end of a table. I found that I needed the flexibility to add/remove the AppCDS setup from the directory, and the client.sh tool.
I added options in the JSON to control removal of appcds. Adding this will remove the appcds from the
"webclient_appcds_jvmargs": "NONE",
and some more control over the appcds configuration:
"webclient_memory": "128m",
"webclient_appcds_archive": "/home/rfb/projects/hotel_dev/deploy/appcds/client/default.jsa",
I did that to easily swap back to the non-appcds method, so I could get the 3rd row in the below. The first is using the manifest-only method, the second is passing the static classpath, and the third is the original configuration.
MODE #Up PeakRSS Rss Pss SharedCln PrivClean PrivDirty ARCHIVE
(MB) (MB) (MB) (MB) (MB) (MB)
default 1 265.5 265.4 251.8 23.0 4.7 237.8 mapped
default 1 374.3 374.3 360.7 23.0 22.9 328.4 mapped
default 1 318.5 318.5 304.0 24.7 0.9 292.9 absent
Notes:
- Rows accumulate across runs (server bounces between configs). Use --reset on
the FIRST run of a fresh comparison to clear old rows.
- ARCHIVE=mapped confirms the .jsa is actually in use for that webClient.
- No ToSettle here: the process was already running, so startup time can't be
measured after the fact (use appcds_mem.sh for the command-line client to get that).
#184 Updated by Roger Borrello about 1 month ago
I checked in revision 206 of hotel so it is more reviewable. The JSON format contains the appcds values in their own section. Sample:
{
"server_xml_file": "server.xml",
"directory_xml_file": "directory.xml",
"spawner_path": "/opt/spawner_chui/spawn",
"client_start_dir": "/home/rfb/projects/hotel_dev/deploy/client",
"appcds" : {
"client_lib_path": "/opt/fwd-deploy/client/lib",
"webclient_appcds_jvmargs": "-Xshare:auto -XX:SharedArchiveFile={archive}",
"webclient_appcds_archive": "/home/rfb/projects/hotel_dev/deploy/appcds/client/default.jsa"
},
"webclient_memory": "128m",
"dateFormat": "mdy",
"numberGroupSep": ",",
"numberDecimalSep": ".",
"p2j_entry": "login.p",
"pkgroot": "com.goldencode.hotel",
"propath": ".:",
"search_path": ".",
"path_separator": ":",
"file_separator": "/",
"case_sensitive": "TRUE",
"os_user": "rfb",
"server_log": "/home/rfb/projects/hotel_dev/deploy/logs",
"client_log": "/home/rfb/projects/hotel_dev/deploy/logs",
"embedded_host": "localhost",
"admin_port": 8443,
"dbnames": "hotel",
"hotel": {
"dbtype": "h2",
"collation": "en_US@iso88591_fwd_basic",
"dbhost": "localhost",
"dbpath": "/home/rfb/projects/hotel_dev/deploy/db"
}
}
I left the memory value outside, because it is a good value to be able to configure with/without AppCDS involvement.
#185 Updated by Teodor Gorghe about 1 month ago
Roger, use this list for LstExporter and share the results:
com.goldencode.p2j.main.ClientDriver \ -com.goldencode.p2j.testengine \ -com.goldencode.p2j.uast \ -com.goldencode.p2j.soap \ -com.goldencode.p2j.security \ -com.goldencode.p2j.schema \ -com.goldencode.p2j.scheduler \ -com.goldencode.p2j.persist \ -com.goldencode.p2j.convert
#186 Updated by Roger Borrello about 1 month ago
Teodor Gorghe wrote:
Roger, use this list for
LstExporterand share the results:
I will get to this as soon as I can.
#187 Updated by Roger Borrello about 1 month ago
Teodor Gorghe wrote:
Roger, use this list for
LstExporterand share the results:
A run with 5 clients yielded:
Launcher: /home/rfb/projects/hotel_dev/deploy/client/client-terminal.sh
Clients per run: 5; settle: 15s; client args: (none)
MODE #Up PeakRSS Rss Pss SharedCln PrivClean PrivDirty ARCHIVE ToSettle STATUS
(MB) (MB) (MB) (MB) (MB) (MB) (s)
appcds 5 1411.7 1379.9 1189.8 226.8 0.1 1153.1 mapped 4.6 ok
no-appcds 5 917.1 915.2 799.0 133.9 0.0 781.3 absent 5.1 ok
Reading the table:
- ARCHIVE=mapped means the .jsa is really mapped in; =absent means -Xshare:auto
silently skipped it (classpath mismatch) -- then 'appcds' isn't using CDS at all.
- ToSettle is wall-time to the last RSS increase (warmup proxy). CDS should make
the 'appcds' value smaller -- that startup speedup is its main single-client win.
- Pss splits shared pages across mappers. With --clients >1 and ARCHIVE=mapped,
compare total Pss (and SharedClean): appcds should win as K grows, because the
one archive is shared across all K JVMs. At K=1 appcds often ties or loses on RSS.
- 'no-appcds' also loads the full library set, so part of any delta is footprint.
I reran after not creating the static lst:
| MODE | #Up | PeakRSS (MB) | Rss (MB) | Pss (MB) | SharedCln (MB) | PrivClean (MB) | PrivDirty (MB) | ARCHIVE | ToSettle (s) | STATUS |
|---|---|---|---|---|---|---|---|---|---|---|
| appcds | 5 | 868.6 | 841.2 | 719.6 | 141.1 | 0.0 | 700.1 | mapped | 4.8 | ok |
| no-appcds | 5 | 935.7 | 929.5 | 813.7 | 133.5 | 0.0 | 796.0 | absent | 5.9 | ok |
#188 Updated by Teodor Gorghe about 1 month ago
Make sure that CDS is actually working. Check it using jcmd <PID> VM.metaspace, it seems to me that CDS is not working.
How much the archive size has been reduced? From my setup, it was reduced from 74M to 71M. The generated .lst from LstExporter should have around 4k classes.
#189 Updated by Teodor Gorghe about 1 month ago
Do you think it is reasonable to use just the listing files just from java -cp p2j.jar:... com.goldencode.p2j.main.ClientDriver?
What is RSS on a application with lots of GUI elements?
#190 Updated by Roger Borrello about 1 month ago
Teodor Gorghe wrote:
Make sure that CDS is actually working. Check it using
jcmd <PID> VM.metaspace, it seems to me that CDS is not working.
I updated #11326-187 to include a table for a run of 5 client.sh against the non-static list (using meta data classpath).
Then I started a web-client (ChUI). Show jcmd output
How much the archive size has been reduced? From my setup, it was reduced from 74M to 64M. The generated
.lstfromLstExportershould have around 4k classes.
Without using the LstExporter the directory is below. .jsa is 21M The default.lst contains 2006 lines (no comments).
-rw-rw---- 1 rfb rfb 35 Jun 18 08:32 default.cpath -r--r----- 1 rfb rfb 21716992 Jun 18 08:32 default.jsa -rw------- 1 rfb rfb 98555 Jun 18 08:32 default.lst
When I run LstExporter with your revised parameters, .jsa is 165M. The .lst has 21,946 lines.
-rw-rw---- 1 rfb rfb 35 Jun 18 08:48 default.cpath -r--r----- 1 rfb rfb 165281792 Jun 18 08:48 default.jsa -rw-rw---- 1 rfb rfb 1062583 Jun 18 08:47 default.lst
Is that what you were looking for? Have you tried this?
#191 Updated by Roger Borrello about 1 month ago
Teodor Gorghe wrote:
Do you think it is reasonable to use just the listing files just from
java -cp p2j.jar:... com.goldencode.p2j.main.ClientDriver?What is RSS on a application with lots of GUI elements?
I can either port this over to hotel_gui, or patch 9866c and run the customer app... I'll start the 9866c build, as I already have this ported to the customer app.
#192 Updated by Teodor Gorghe about 1 month ago
165M is huge, I have didn't saw an archive so big which was generated by deploy_appcds.sh
This is what I ran to manually test this (in lib.client):
java -cp p2j.jar com.goldencode.util.LstExporter com.goldencode.p2j.main.ClientDriver -com.goldencode.p2j.testengine -com.goldencode.p2j.uast -com.goldencode.p2j.soap -com.goldencode.p2j.security -com.goldencode.p2j.schema -com.goldencode.p2j.scheduler -com.goldencode.p2j.persist -com.goldencode.p2j.convert -o classes.lstOutput
java -cp p2j.jar -Xshare:dump -XX:SharedClassListFile=classes.lst -XX:SharedArchiveFile=archive.jsaOutput
ls -ll *.jsa *.lstOutput
#193 Updated by Roger Borrello about 1 month ago
Teodor Gorghe wrote:
165M is huge, I have didn't saw an archive so big which was generated by
deploy_appcds.sh
This is what I ran to manually test this (inlib.client):
I need info on lib.client. What is it used for? I don't see reference to it anywhere (besides the build.xml)
#194 Updated by Roger Borrello about 1 month ago
I corrected what was creating a huge archive, and ported to hotel_gui. I was recursing through all the *.jar files.
Here is a table of my runs...
| MODE | #Up | PeakRSS (MB) | Rss (MB) | Pss (MB) | SharedCln (MB) | PrivClean (MB) | PrivDirty (MB) | ARCHIVE | ToSettle (s) | STATUS |
|---|---|---|---|---|---|---|---|---|---|---|
| no-appcds-swng | 1 | 292.9 | 292.9 | 267.9 | 34.1 | 1.3 | 256.3 | absent | ||
| no-appcds-web | 1 | 360.5 | 360.5 | 336.7 | 32.4 | 0.6 | 327.5 | absent | ||
| appcds-swing | 1 | 306.5 | 306.5 | 281.4 | 34.2 | 1.2 | 269.8 | absent | ||
| appcds-swng2 | 1 | 272.0 | 272.0 | 246.9 | 34.2 | 1.2 | 235.3 | absent | ||
| appcds-web | 1 | 315.9 | 315.9 | 293.1 | 30.3 | 12.4 | 273.2 | mapped | ||
| appcds-swg3 | 1 | 260.7 | 260.7 | 227.3 | 44.9 | 0.2 | 214.3 | mapped |
- Rows accumulate across runs (server bounces between configs). Use
--reseton the FIRST run of a fresh comparison to clear old rows. - ARCHIVE = mapped confirms the
.jsais actually in use for that Client.
Notice ARCHIVE is absent for the first 2... that was intentional. I allow the --no-appcds option to client.sh, but also the prepare_dir.sh can disable in the directory.xml so that web clients can be tested. The next pair of runs were swing runs (./client.sh --swing) but they failed because of the classpath. I think that you know that the same exact classpath needs to be used at this end as was used to prepare the archive. This is the reason to add default.cpath as a generated file which contains the classpath as used in the archive generation... so there isn't any guesswork. I will have to add that back into getcp.sh and client.sh.
The last 2 are properly configured (directory.xml and classpath for client.sh).
The web client uses a different scheme for the classpath... the manifest must contain it. Is that possible to do with the ClientDriver when using the runlist created only by -XX:DumpLoadedClassList and not the static list? I'm asking because of ignorance.
#195 Updated by Roger Borrello about 1 month ago
I ran the Swing client test with 2 and 5 concurrent clients:
| MODE | #Up | PeakRSS (MB) | Rss (MB) | Pss (MB) | SharedCln (MB) | PrivClean (MB) | PrivDirty (MB) | ARCHIVE | ToSettle (s) | STATUS |
|---|---|---|---|---|---|---|---|---|---|---|
| appcds | 2 | 534.4 | 524.2 | 450.7 | 90.0 | 0.1 | 431.7 | mapped | 3.0 | ok |
| no-appcds | 2 | 580.9 | 580.9 | 517.7 | 74.6 | 0.1 | 503.8 | absent | 4.1 | ok |
| appcds | 5 | 1412.9 | 1433.5 | 1229.9 | 225.4 | 0.0 | 1201.9 | mapped | 15.0 | ok |
| no-appcds | 5 | 1600.1 | 1572.6 | 1401.1 | 186.7 | 0.0 | 1379.7 | absent | 8.6 | ok |
So appcds wins.
#196 Updated by Roger Borrello about 1 month ago
I checked in updates to both hotel and hotel GUI that are able to configure AppCDS (and not configure). The template preparation was updated, although it simply asks if you want a sample added to your project, and uses standard settings to add to the JSON.
#197 Updated by Teodor Gorghe about 1 month ago
I would need to schedule a meet with you.
Today, 10:00 AM GMT-4 time, are you available (this is 17:00 on my time)?
#198 Updated by Radu Apetrii about 1 month ago
Teodor Gorghe wrote:
I would need to schedule a meet with you.
Today, 10:00 AM GMT-4 time, are you available (this is 17:00 on my time)?
AFAIK, Roger doesn't work on Fridays, so you'll probably have to wait until Monday.
#199 Updated by Teodor Gorghe about 1 month ago
Radu Apetrii wrote:
Teodor Gorghe wrote:
I would need to schedule a meet with you.
Today, 10:00 AM GMT-4 time, are you available (this is 17:00 on my time)?
AFAIK, Roger doesn't work on Fridays, so you'll probably have to wait until Monday.
Ok, I will wait for him for a proposal.
#200 Updated by Teodor Gorghe 29 days ago
Roger, for now, the stats showed in last notes, convinced me that having an almost full coverage archive, is not the most efficient because not every project reaches all possible path from FWD bytecode.
For now, I think we can disable LstExporter by default and use the minimal runtime generation.
In the future, I think we can create a minimal FWD server - FWD client setup, which loads several basic widgets.
This would also be very useful when moving to Java 25 because we can use AOT, which shares the code cache across FWD clients.
#201 Updated by Teodor Gorghe 29 days ago
Also, I have checked the hotel changes.
Is not a good time to refactor getcp.sh to generate a lightweight class path, because adding dependency jar files is not required.
#202 Updated by Roger Borrello 29 days ago
Teodor, thank you for pressing on in my absence. The getcp.sh helper was created to move so much logic out of client.sh and server.sh. It needs to stay up-to-date. If we could get the complexity of the logic for finding jars into this AppCDS standard, then would could just pass the classpath over as the .cpath file does. That would be a win.
There is something bothering me about the directory.xml changes I made, and that is the libPath. I went to some effort to only include the libPath section in the directory when AppCDS is configured:
<node class="string" name="libPath">
<node-attribute name="value" value="{client_lib_path}"/>
</node>
If this section can be included whether or not AppCDS is configured, that would remove some complex logic from prepare_dir.sh. I thought it safer to not introduce additional configuration items if we were not using AppCDS. (Because what would be appropriate for {client_lib_path} if that is the case?)
#203 Updated by Teodor Gorghe 29 days ago
If there is no libPath, the server will use the deploy/lib or /opt/fwd-deploy/convert/lib libPath, depending what is the used p2j.jar for server runtime.
#204 Updated by Roger Borrello 29 days ago
Teodor Gorghe wrote:
That addresses if theIf there is no
libPath, the server will use thedeploy/libor/opt/fwd-deploy/convert/liblibPath, depending what is the used p2j.jar for server runtime.
libPath is needed, but not found in the directory. But what I'm talking about is avoiding conditionally including it in the directory, and just including it all the time in the template:
- Is it OK to have it in the directory, but not need it?
- And in that case, it wouldn't really matter what the value is set to, correct?
#205 Updated by Teodor Gorghe 29 days ago
What do you mean by not needing?
In case of not using AppCDS, the spawned clients will still use libPath. It was designed to use for client lib jars, which load less dependencies into memory, resulting to a smaller heap memory consumption.
If there is no client_lib_path into prepare json file, both solutions are good. I have included it marked as default to ../lib because it's the most common setup.
Your solution seems more right, but adds more complexity in prepare_dir.sh script.
#206 Updated by Teodor Gorghe 29 days ago
Of course, if that value is incorrect, clients will fail to spawn.
#207 Updated by Roger Borrello 29 days ago
Teodor Gorghe wrote:
What do you mean by not needing?
When the entire library is passed in the classpath... the previous way classpaths were build.
In case of not using AppCDS, the spawned clients will still use libPath. It was designed to use for client lib jars, which load less dependencies into memory, resulting to a smaller heap memory consumption.
If there is no client_lib_path into prepare json file, both solutions are good. I have included it marked as default to
../libbecause it's the most common setup.
Your solution seems more right, but adds more complexity inprepare_dir.shscript.
Since the code update in prepare_dir.sh behaves properly if no appcds information is found in the JSON, and builds the directory without any libPath, I believe we should leave it as currently implemented.
We should get #11472-37 reviewed so we can allow the customer to test ASAP.
#208 Updated by Roger Borrello 21 days ago
Teodor, should fwdspi.jar be part of the archiveClient in build.gradle? In my Dockerfiles I copy it to the project lib directory:
# Step 9/45
RUN cp ${FWD_LIB}/build/lib/fwdspi.jar /opt/${PROJECT}/lib
but that file is not part of the client archive, and this step fails. Previously we had been using the convert archive, but we wanted to use the slimmer library source.
#209 Updated by Teodor Gorghe 20 days ago
Can you tell in which docker file did you found this issue?
#210 Updated by Teodor Gorghe 20 days ago
Also, why FWD_LIB is the client archive? Shouldn't be the convert archive (/opt/fwd)?
For hotel_gui, in /opt/.../lib should be the converted application files. fwdspi.jar also needs to be there for H2 CollatorProvider. It is only used for FWD server/conversion.
#211 Updated by Roger Borrello 20 days ago
Teodor Gorghe wrote:
Can you tell in which docker file did you found this issue?
In trying to duplicate the customer scenario in hotel_chui for simplification, I've found that the customer's docker/fwd_4.0_ubuntu_client_Dockerfile is not supposed to try to copy fwdspi.jar, as it is not used on the client. So I will be updating their Dockerfile.
Nothing to see here.
#212 Updated by Roger Borrello 20 days ago
Teodor Gorghe wrote:
Also, why
FWD_LIBis the client archive? Shouldn't be the convert archive (/opt/fwd)?
FWD_LIB is always set to /opt/fwd. But that symlink should be /opt/fwd-convert or /opt/fwd-client as necessary. I don't think that is an issue, because most scripts and JSON are explicitly using /opt/fwd-client.
For
hotel_gui, in/opt/.../libshould be the converted application files.fwdspi.jaralso needs to be there for H2 CollatorProvider. It is only used for FWD server/conversion.
Yes... found that.
#213 Updated by Teodor Gorghe 20 days ago
Roger Borrello wrote:
Teodor Gorghe wrote:
Can you tell in which docker file did you found this issue?
In trying to duplicate the customer scenario in hotel_chui for simplification, I've found that the customer's
docker/fwd_4.0_ubuntu_client_Dockerfileis not supposed to try to copyfwdspi.jar, as it is not used on the client. So I will be updating their Dockerfile.Nothing to see here.
Ok, that makes sense.





