ADF is a highly productive but somewhat complex framework, and has evolved to optimize the default settings for better performance. But there are many options which depend on the specific application and use case, so here are are few pain points and solutions that you should consider for better performance of your ADF applications.
It is very important to note that performance should be considered from the design phase of your application vs. an afterthought. This seems obvious, but too often we see customers/developers struggle to make sure that happens.
- Make sure to “appropriately set Row Level Bind Values for View Accessors to false or true” as necessary. See blog for more details. This value would mostly be set to “false”. Be aware that JDeveloper at times resets this value to blank, which means true and it may not be desired for your situation.
- There is a memory leak in this situation, if your Application Modules are alive for longer duration without being recycled.
- You will also notice Performance degradation over time.
- You can use DBSequence for generated key attributes or you can override create method to programmatically generate key.
- Either option works, but if you want to enable JDBC Batching for Performance, you can not use DBSequence.
- It is best to standardize on one option for entire development team to promote consistency. So i would recommend use of create method or groovy expression to programmatically generate keys. This is very well documented in various blogs. Here is sample groovy code.
(new oracle.jbo.server.SequenceImpl("MY_TABLE_SEQ", adf.object.getDBTransaction())).getSequenceNumber()
- ADF BC State Persistence
- ADF BC will persist it’s state to PS_TXN table. You will need to work with your Database team to tune access to this table, if you run into performance issues.
- Setup at least daily purge for PS_TXN table.
- SQL Scripts for creating tables (adfbc_create_statesnapshottables.sql) and purge (bc4jcleanup.sql) are available in JDeveloper installation at <JDeveloper Install Directory>\oracle_common\modules\oracle.adf.model_12.1.3\bin.
- Your goal should be minimize such persistence and subsequent activation as that can deteriorate performance of your application. This can be achieved by setting up higher value for Application Module reference pool. Configure this value such that reference pool number * number of managed servers in cluster equals to total number of unique sessions in 30 minutes. This is just a simple rule that i have devised, note that this will require you to tune JVM memory settings as more number of Application module will be active in memory.
- View Object tuning
- You can use Forward Only mode in non UI access of View Object. For example, background processing. Forward Only access is very efficient.
- You may have to use Query Hint like FIRST_ROWS(1001), to give hint to database optimizer about your intentions that you are only interested in first 1001 rows.
- Use Retrieve in Batches of Range Size +1. This will allow efficient retrieval of data from database ResultSet. This is extremely important as this value defaults to 1 when you create View Object.
- Avoid persisting Transient attributes, if their values can be derived from other attributes. Be careful when checking “Including All Transient Values”.
- Disconnect Application Module on Release.
- ADF will not release database connection back to Data Source by default, which can lead to high connection usage and application may eventually get in to hung situation if you run out of Data Source connections.
- Setting this option will make sure that connection is released back to Data Source pool and you can keep more number of active application modules in memory without requiring high number of data source connections.
- Tune org.apache.myfaces.trinidad.CLIENT_STATE_MAX_TOKENS appropriately.
- Token based client side state saving is enabled by default. Browser will pass token indicating reference to page state and page state is stored in HTTP Session. You can inspect token value using tool like Fiddler.
- There are 15 such page state instances maintained in HTTP Session, which can lead to unnecessary memory usage for applications with large number of users.
- You can not set this value to 1, as you need to allow for use of Back button and Chrome & Firefox share session across all tabs & windows. So if you set this value to 1, Users will be able to launch only 1 tab for that application.
- Cache static content like .js, .css, .png etc.
- You can cache static content in your Load Balancer.
- Make sure that browser history is also maintained. IE has settings that can clear Browser History on exit.
- Monitor access logs to validate content caching.
- If using Oracle Access Manager
- Default settings of Oracle Access Manger prevents caching of content on Client end, you will need to correct the cache-control header variables in OAM, so that it does not insert headers to disable caching.
- Enable Compression as needed.
- ADF significantly reduces bandwidth requirements over traditional (non AJAX) JSP applications.
- If you have users connecting over slower connections, you may want to enable compression to reduce communication time.
- Enable Garbage collection logs.
- Add -verbose:gc to server start arguments. If you are using JRockit, add -XverboseTimeStamp as well.
- Enable Heap dump on Out of Memory.
- Add -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/<Server Name> to Server Start parameters. Make sure you have enough space for this directory and <Server Name> folder is created. Ideally, you should just use a separate mount point specifically for Heap Dumps if running on UNIX.
- You can use Eclipse MAT, which seems to work perfectly for heap analysis.
- Add command line parameters to allows for JMX connection from JRockit Mission Control or JConsole.
- Add -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=<Port#> to Server Start Parameters. Define a new port for each Server for this purpose.
- You can also run Profiling using JRockit Mission Control, to monitor time spent in specific methods. This is unique feature of JRMC that is not yet available in JConsole.
- Print time spent in access logs.
- Use Extended format for HTTP Logs with c-ip date time cs-method cs-uri sc-status bytes time-taken.
- If you have Apache or OHS in front of WebLogic server, make sure to update it’s log format to print time spent at the end.
- Use <statement-timeout>100</statement-timeout> for your Data Sources to time out long running queries. This example is set for 100 seconds timeout, you can tune it as per your needs.
- You can customize the Exception Handler to provide proper message to user for such timeout situations.
5 thoughts on “Tuning best practices for ADF applications”
While I applaud your initiative of blogging about ADF performance tuning and I agree with most of your writing, there are few conclusions I would debate in your above post:
“Make sure to set Row Level Bind Values for View Accessors. See blog for more details.
There is a memory leak in this situation, if your Application Modules are alive for longer duration without being recycled.
You will also notice Performance degradation over time.”
I am sorry to say, but your interpretation of “Row Level Bind” is incorrect. On the contrary, the value should stay on FALSE as much as possible. You can see this blog for details about performance degrading when the value is set on true.
For further understanding how “Row Level Bind” behaves under the hood, please see:
“Setup at least daily purge for PS_TXN table.”
If you need to purge your PS_TXN table, than is a clear sign you are not tuning your Application Modules properly.
You are definitely having lots of activation happening.
I am sorry I may sound harsh, but I think is important to pass to your blog readers the most accurate info possible.
1) Row level binds. I meant to say “appropriately set true or false for this”, did not mean to say set to true all the time. I will correct it. I agree that Row level binds value should stay false for most part, but issues comes as JDeveloper (11g specifically) resets this value to blank when you make changes to View Object. And blank means true, which is not the desired setting most of the time. So unfortunately that is bad default. If developer realizes this before committing code, that would be nice, but that does not happen always.
2) Later in that section, i have suggested to minimize such persistence, but practically you may not be able to achieve that 100% of time, so setting purge is good idea along with definitely tuning application module pool.
Thank you so much for comment, it was very good feedback and clarification.
Hi Chandresh Patel.
I have read many posts on internet for question ” what’s different between Request Scope and BackingBean scope ? “. But I still can’t get clearly answer :(. Can you help me expand that ?
Backing bean scope is somewhat similar to Request scope in terms of how long it survives, but it is limited to taskflow or declarative component. If you have two taskflows (with fragments) on page, there is one request scope but there are two backing bean scopes for each taskflow. You should mostly use backing bean scope with ADF taskflow instead of request scope.
Thanks Chandresh Patel