function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Brad RileyBrad Riley 

Viewstate size within Visualforce pages

Hi all,

Does anyone know a way to cut down the size of the viewstate that gets posted to and from the server?  We are finding very noticeable performance hits when we do AJAX postbacks (or any kind of postback really).  We have done some investigation and have noticed the viewstate is very large for what we are actually rendering to the browser.  For example:

<apex:page>

           <apex:form>

            </apex:form>

</apex:page>

ViewState size = 1772 bytes

<apex:page standardController="Case">

            <apex:form>

                  <table>

                        <tr><th>Head</th></tr>

                        <tr><td>Content</td></tr>

                  </table>

                  <c:TestComponent />

            </apex:form>

            <apex:outputField value="{!Case.Contact.Name}" />

            <apex:outputPanel />

            <apex:outputText value="Test" />

</apex:page>

<apex:component>

      <table>

            <tr><td>Content In Component</td></tr>

      </table>

</apex:component>

ViewState size = 3756 bytes

As you can see these are simple examples that we have slowly built out to monitor the increase in viewstate.  Naturally as our pages get more complex the viewstate gets excessively large, slowing down the round trip to the SF servers.

Therefore, the questions I have are:

Can we configure the viewstate for each component like ASP.Net allows (or for the entire page)?


Cheers

TehNrdTehNrd
Unless you are on a 56K connection how is a 3KB viewstate causing performance issues?

Regardless, take a look at the actionRegion tag.

-Jason

Edit: I guess those are just example sizes above. How big are the larger sizes that are giving you issues?



Message Edited by TehNrd on 07-20-2008 09:08 PM
Brad RileyBrad Riley

I agree the samples are very small, but in effect, the visualforce page is displaying nothing.  We have a very complex page, with a substantially sized  viewstate, which is used for loading invoices and payments.  It needs to be very fast and after each payment we have to recalculate (using an ajax postback) some numbers and then display the updated result.  During the postback, the viewstate size is causing a 2-3 second delay per payment line.  If the viewstate was cut down to only postback what we actually are using for the calculation (ie one or two fields) it would make a massive difference.

Cheers

TehNrdTehNrd
Makes sense, put the actionRegion tags around the fields that you want sent for processing.

Also check the debug log to see your most expensive methods/soql calls to see if anything can be optimized on the processing side.


Message Edited by TehNrd on 07-22-2008 10:46 PM
AFawcett (CODA)AFawcett (CODA)

Hi Brad,

Can you tell us if actionRegion actually made a difference for you in this case?

Cheers,

Andy.

dchasmandchasman
apex:actionRegion will not impact viewstate - the viewstate blob is indivisible. There are, however, quite a few things you can and should do to manage viewstate size. In fact, when we see viewstate sizes greater than say 20K that is typically an indicator that the wrong things are being held in viewstate. Any non-transient data members (see the documentation for the transient apex language keyword) in your controller, controller extension(s), objects that are reachable via a non-transient reference from either the controller /or extensions, etc all contribute to viewstate. The complexlty of your visualforce markup should be by far the smallest contributor to viewstate size - you will never get viewstate to be 0 because visualforce itself needs a small amount of space to store its own housekeeping data.

Viewstate should really contain only things like work in progress data (e.g. current objects being edited, multipage wizard transient stuff, etc). Information that can be reconstructed by using SOQL queries on post back should not be stored - just requery instead. Also, I occasionally introduce a custom object for the express purpose of managing work in progress data server side and only store the object's id in my controller. In my case this was not to reduce viewstate as much as it was to provide an autosave like behavior that would survive browser sessions but the same approach could be leveraged here - although I doubt we'll need to go to that level of sophistication to get your viewstate back in line.

Finally, something that is often overlooked is the low tech approach of not using action method bound elements and switching to apex:ouputLink or some other non-action method mechanism and just using basic HTTP parameter passing to invoke a viewstateless action implemented via <apex:page action> for example.

Hopefully this helps - if you are still stuck please post an example of your heaviest page/controller/extensions and we'll see about putting them on a diet.


Message Edited by dchasman on 07-23-2008 08:07 AM
TehNrdTehNrd
Thanks for clarifying Doug.

My bad for sending you down the wrong path with actionRegion
dchasmandchasman
FYI we are working to add more information/best practices type information to the VF documentation w.r.t. viewstate - this is one of those concepts that most of the time you do not need to go into much detail but when you need it you really need it.
Mark YoungMark Young
Warning: long post!
 
Thanks Doug,
 
I've done some more investigation into this and would really appreciate any feedback.  I come from a .Net background and have pretty solid knowledge of the low level workings of ASP.Net (so forgive me for too many comparisons).
 
The following appear to be major issues when developing large pages (especially with repeaters and ajax):
  • All components add to viewstate regardless of whether values are specified in page definition or through a coded value.  I.e. even values that will be recreated each time are stored when they don't need to be.  .Net uses a property tracker which only serialises out properties that have changed after the control's OnPreInit phase.
  • When nesting components and using a UserControl / modular style of development for consistency / ease this viewstate size can increase very quickly.  As shown below, it's not hard to get to 30k just from components (i.e. without any variables being stored from controllers) - this significantly affects the usefulness of any ajax methods.
  • Components inside ajax panels (i.e. panels that are being rerendered) are added to the 'Ajax-Update-Ids' field for ajax postbacks.  When a repeater is involved (especially when controls are nested quite a long way down) this can lead to a huge amount of extra data being passed around.

What we're seeing is:

  • When a page is first being built up, response times from ajax sections are very fast.  However, once that page gets more data / components on it (even outside of ajax update sections) the page response times slow down significantly.  The slow down experienced by the user if much more than the difference in the 'render time' returned in the debug data although that is also increased.  We assume that page request & responses going from ~5k to ~30k is having a significant impact on it.
  • Interestingly, built in salesforce pages don't have this issue, meaning Visualforce pages (even near replicas of salesforce pages) are at a distinct performance disadvantage.

To demonstrate viewstate sizes:

Code:
<apex:page standardController="Contact">
    <apex:form>
        <apex:inputField value="{!Contact.FirstName}" />
    </apex:form>
</apex:page>

Has about 3265 bytes of viewstate.

Each extra inputField adds about 108 bytes to the viewstate length.

The following basic component called ErrorPanel can be used to wrap an error message (this is example only):

Code:
<apex:component>
    <apex:attribute name="hasError" type="String" required="false" description="Sets whether this panel is in an error state" />
    <apex:attribute name="errorText" type="String" required="false" description="The error text to display when in error" />
    <apex:outputPanel rendered="{!hasError}" layout="none">
        <strong>Error:</strong> {!errorText}
    </apex:outputPanel>
</apex:component>

Adding this to the page adds another 660 bytes.

Then wrap this in another component below which we can flesh out to provide for other common details:

Code:
<apex:component >
    <apex:attribute name="hasError" type="String" required="false" default="false" description="Sets whether this panel is in an error state" />
    <apex:attribute name="errorText" type="String" required="false" default="" description="The error text to display when in error" />
    <apex:outputPanel >
        <apex:componentBody />
        <c:ErrorPanel hasError="{!hasError}" errorText="{!errorText}" />
    </apex:outputPanel>
</apex:component>

Now, our page which looks like:

Code:
<apex:page standardController="Contact">
    <apex:form>
        <apex:pageBlock>
            <apex:pageBlockSection title="Test Viewstate">
                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="First Name" />
                    <c:ValidatedField hasError="false" errorText="Please enter first name">
                        <apex:inputField value="{!Contact.FirstName}" />
                    </c:ValidatedField>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="Last Name" />
                    <c:ValidatedField hasError="false" errorText="Please enter last name">
                        <apex:inputField value="{!Contact.LastName}" />
                    </c:ValidatedField>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

has gone to 5569 of Viewstate which each new field adding ~500 bytes.  

You can easily imagine a page of 15 fields getting up to 15k of Viewstate without having to add too much complexity, especially when you start throwing repeaters and outputPanels into the mix.

 

The second issue that comes up is when doing the following:

Code:
<apex:page standardController="Contact">
    <apex:form>
        <apex:pageBlock>
            <apex:pageBlockButtons>
                <apex:commandButton value="Submit" rerender="ajaxSection" />
            </apex:pageBlockButtons>
            <apex:outputPanel id="ajaxSection">
                {!NOW()}
                <apex:pageBlockSection title="Test Viewstate">
                    <apex:pageBlockSectionItem>
                        <apex:outputLabel value="First Name" />
                        <c:ValidatedField hasError="false" errorText="Please enter first name">
                            <apex:inputField value="{!Contact.FirstName}" />
                        </c:ValidatedField>
                    </apex:pageBlockSectionItem>
                    <apex:pageBlockSectionItem>
                        <apex:outputLabel value="Last Name" />
                        <c:ValidatedField hasError="false" errorText="Please enter last name">
                            <apex:inputField value="{!Contact.LastName}" />
                        </c:ValidatedField>
                    </apex:pageBlockSectionItem>
                </apex:pageBlockSection>
                <apex:pageBlockSection columns="1">
                    <apex:outputPanel id="casePanel">
                        <apex:repeat value="{!Contact.Cases}" var="caseItem">
                            <apex:outputPanel id="caseItemPanel" layout="none" rendered="{!caseItem.Priority = 'Medium'}">
                                <p>   
                                    <apex:outputLabel value="Id:" for="caseId" />
                                    <apex:outputField id="caseId" value="{!caseItem.Id}" />
                                    <apex:outputField value="{!caseItem.Subject}" />
                                    <apex:outputField value="{!caseItem.Status}" />
                                </p>
                            </apex:outputPanel>
                        </apex:repeat>
                    </apex:outputPanel>                  
                </apex:pageBlockSection>
            </apex:outputPanel>
        </apex:pageBlock>
    </apex:form>
</apex:page>


 
The ajaxSection has a rerender on it which includes a repeater and various other controls (this example is bit contrived... issues become obvious when pages become deep).

Doing an ajax postback contains a hidden field with something similar to:

Code:
<meta name="Ajax-Update-Ids" content="j_id0:j_id1:j_id2:ajaxSection,
j_id0:j_id1:j_id2:j_id6:j_id7:j_id9:j_id10:j_id12,
j_id0:j_id1:j_id2:j_id6:j_id7:j_id9:j_id10:j_id14,
j_id0:j_id1:j_id2:j_id6:j_id18:j_id20:j_id21:j_id23,
j_id0:j_id1:j_id2:j_id6:j_id18:j_id20:j_id21:j_id25,
j_id0:j_id1:j_id2:j_id29:j_id30:0:j_id46,
j_id0:j_id1:j_id2:j_id29:j_id30:0:caseId,
j_id0:j_id1:j_id2:j_id29:j_id30:0:j_id32,
j_id0:j_id1:j_id2:j_id29:j_id30:0:j_id33,
j_id0:j_id1:j_id2:j_id29:j_id30:0:j_id47,
j_id0:j_id1:j_id2:j_id29:j_id30:2:j_id46,
j_id0:j_id1:j_id2:j_id29:j_id30:2:caseId,
j_id0:j_id1:j_id2:j_id29:j_id30:2:j_id32,
j_id0:j_id1:j_id2:j_id29:j_id30:2:j_id33,
j_id0:j_id1:j_id2:j_id29:j_id30:2:j_id47,
j_id0:j_id1:j_id2:j_id29:j_id30:3:j_id46,..." />


 Every component (at least every one with an id) inside the 'update panel' is included in this list.  When id names are long (with a few more levels) and we've got a few components which we reference via ids for javascript etc this can become huge.

 

With these couple of things we are seeing traffic sizes balloon out (easily up to 50k for both request and response) before adding any "real" viewstate.  It really does appear to be impacting performance, especially over sluggish corporate internet connections.

Hope this adds some more detail - any responses on how to minimize this impact would be appreciated.

Cheers!

Mark
 

dchasmandchasman
Mark -

We are always working to reduce viewstate. So far you are one of the only external devs to bring this up (I have been one of the only folks to pay much attention to viewstate so far - nice to not be alone :-). We're getting reports of good to excellent performance from the majority of folks we work most closely with and partially because of that my team's primary focus has been on rounding out other areas of VF. We're trying to strike a balance between all requirements with ease of use and breadth of offering being the 2 we've placed highest priority on for Winter '09.

Some components definitely contribute more to viewstate bulk than others and it happens that apex:inputField is one of the heaviest  - much of this is because we are leveraging legacy salesforce code inside its implementation.

It took Microsoft more than 4 years to get a even a reasonable story around work in progress state management (I was actually involved in driving some of that work BTW) - Visualforce only GA'ed 3 months ago so we need a bit more runway still (I don't expect it too take anywhere near the time it took MSFT BTW - already been through this more than once).

The longer term plan is to:

- continue to optimize viewstate down to the inidividual component level (ongoing)
- increased use of deltas and better property management (in design)
- (under serious consideration in conjunction with all of the above) move viewstate management to a server side transient store similar to the way we manage api queries and query locators.

Built in pages have little relationship to fully custom, component based, org specific pages - the built in pages are built entirely in Java and have been hand tuned over many many years of in production use. These represent a theoretical ideal for VF at best. I think you will agree that if you take a standard page and add even a couple of scontrols for a very limited type of customization you'll see a very different world of performance.
Mark YoungMark Young

Thanks Doug,

Don't get me wrong, I think you've done an excellent job with the current Visualforce offerings, especially considering it's time to market.

I'll keep a close eye on things, and let you know what components / techniques in page design tend to affect things the most.

Is there a way to get around all of those child component ids being passed back in the ajax response apart from updating a much more specific section?

Cheers,
 
Mark
SimbaSimba
We have a Visalforce page, which takes about 6 seconds to load initially, which is still okay. However, all the subsequent Ajax post backs take about 30 - 40 seconds to load a pageBlockSection.
 
I am sure our Viewstate must be really very large, so I was wondering how can I check the size of the Viewstate, on the Visualforce page.
 
Also, we have a very complex Visualforce page. The data on this page is all coming from the WebService calls, which are typically made one time, and the data is then parsed and all stored in the SF List objects. The SF list objects are then used to display data on the page. If we mark these list objects as transient then I guess we'll need to parse the response again, everytime we make a call to the server, to render the page. Is this a true statement ?
 
Thanks
 
Warm Regards
 
 
 
 
 
dchasmandchasman
Need much more detail to be able to solve this type of performance issue.

On the 30+ seconds for rerender I suspect this is client side issue for a couple of reasons:
  • our servers typically do not allow a request to use that much per request server time (they abort the request to protect the service) and I highly suspect this is client side processing gone wild
  • rerender does less work that a full page request server side and should typically outperform a full page request even with a large amount of viewstate
  • the largest viewstate possible is currently limited to 128K which is a relatively small amount of data to post even if you are at the limit (should not require more than a second worst case)
How many apex:form tags do you have in your page? Currently you get a copy of the serialized viewstate blob (shows up as a hidden input in the HTTP response) per apex:form and depending on the scope of your rerender etc this could be a lot more data than we want...

You are correct about "If we mark these list objects as transient then I guess we'll need to parse the response again, every time we make a call to the server, to render the page. Is this a true statement ?" w.r.t. top viewstate and transient but keep in mind that viewstate is not meant to handle large read only data like this. How big is the information you are holding onto? Is it expensive to retrieve from the web service? Another option could be to snapshot the response in a compact form in a custom object

SimbaSimba
Thanks for replyring to my message. I really appreciate any help in this
 
If Viewstate cannot be large enough, then in that case, our first target should not be to reduce the Viewstate size for increasing the performance.
 
Regarding doing the parsing again, We have a very large response that we get from the client (almost 400 K size). So it takes about 22 seconds just to do the parsing (using XMLStreamReader). Hence it might not be a good idea to do the parsing on every call to the server (on every selection change). We might be able to store these data in the object, but again that'll require saving to the SF objects, every time user makes selection. Not sure how good that would be.
 
For all the susequent calls that we make to server, as seen in the System Log, the Apex methods do not take that long to process. The total processing time on the Apex side is well within 2 secs.
So from that looks like all the time is taken by rendering the page. On our Visualforce UI, we have three sections and each section has about 5 components, though none of them are nested. We also have almost about 2-3 levels of repeat/pageBlockTable. Also we have a hidden section to store (apex:inputHidden) fields, which we render almost everytime a selection is changed. Is there a way to see, the size of each section (pageBlockSection) that gets post back on every render ?
 
Everytime we make a selection, we need to display a Price of that selection and the total price, the whole thik takes about 20-30 sec to load the page again, and the Apex side takes about 2 seconds.
 
Also, let me know if you think it would be helpful to look at the code itself, I can the components code if needed. Or if you need any more information.
 
Thanks again
 
Warm Regards
 
Scott.MScott.M

This is all really great discussion, explains a lot :)

 

We've been struggling with the viewstate for a while now, and while transient is great, in our case we can't use it and here's why. We have a visualforce component that does something like this:

<apex:form>
  <apex:repeat value="{!somelist}" var="object">
    <apex:component1 rendered="object.value == 'component1'" />
    <apex:component2 rendered="object.value == 'component2'" />

    <apex:component3 rendered="object.value == 'component3'" />
    <apex:component4 rendered="object.value == 'component4'" />

    <apex:component5 rendered="object.value == 'component5'" />
    <apex:component6 rendered="object.value == 'component6'" />

    <apex:component7 rendered="object.value == 'component7'" />
    <apex:component8 rendered="object.value == 'component8'" />
 

   </apex:repeat>

</apex:form>

 

What we're doing with this is kind of a sudo dynamic visualforce. Transient won't work in our case because all of the  components use the same controller. So if component1 is rendered we actually want to maintain state for component1 but we don't want to maintain state for the rest of the components. Since they all make use of the same controller if we set the controller's variables to transient then the component we're rendering won't maintain state. If we don't set the variables to transient our viewstate get's cluttered with things we know we don't need in there on top of the things we can't control like the added data for the unrendered components. There are a few solutions we can think of:

  1. Dynamic Visualforce would solve the problem since we wouldn't have to include the unrendered components but we're not holding our breath for it to be released soon.
  2. Another simple solution would be to provide an includeInViewstate attribute on components.
  3. Increase the viewstate limit - it's a terrible solution but it would at least give us a little bit as we wait for better solutions

We're keeping our eye out for updates and trying to find creative solutions in the meantime :) 

 

Thanks for all your guys hard work!

 

Scott

Scott.MScott.M

A new idea has been posted about this, a year later. I would encourage everyone on this thread and anyone who reads this thread to vote for it. Let's get some visibility on this problem and hopefully some improvements in the next year.

 

http://sites.force.com/ideaexchange//apex/ideaView?id=08730000000JqtDAAS

gernotgernot

We are developing a web platform with VF pages and also run into a very big viewstate hassle - the page delivers 10 times 44000 characters of viewstate, which is approx 440kb of content within a total of 500kb per page.

 

I am stuck within the research of how to reduce the viewstate overhead and just found recommendations like "optimize the amount of information kept in viewstate" but no information about HOW to achieve this.

 

In .NET it is just a configuration issue - same should be possible in SFDC...

 

Any hints are highly appreciated.

AFawcett (CODA)AFawcett (CODA)

We have found the standard VF compnents themselves add overhead to the viewstate in addition to member variables you put i nyour controller. Try reviewing how many <apex:ouputField> and other tags you have and see if you can reduce these or use regualr HTML tags instead. Also worth checking out the Viewstate debugger tool, this gives you a great insight into the contents of the view state, both as regards Salesforce contents and your own.

gernotgernot
We tried to optimize by cutting everything down to minimum. It took us almost 2 days of code inspection, with the result of reducing the viewstate from 44kB to 35kB - which is in total 350kB on each page load, just for the viewstate. Unacceptable, IMHO.
A_Li_NA_Li_N

In general our pages load quite quickly without regard to viewstate items.  There is one, though, that takes 4-8 seconds for each 'refresh' of the table.  The viewstate size is at 16kb as I'm looking at it right now with 71 items in the pageBlock table.  10.85kb of that 16kb is 'Internal' of which I have no idea how to reduce.

 

My question is: Why does a refresh of the table take 4-8 seconds to build a 16kb viewstate?  I've checked the debug log and the performance is good until the viewstate building; the query/processing takes about 1.5 seconds, the viewstate takes the rest of that time.  Why is this?

 

My page structure is like this:
form

actionFunction

actionFunction

actionFunction

actionFunction

actionPoller

pageblock 

pageblocktable (12 columns)

headers: commandLink | commandLink | commandLink | commandLink | commandLink | text | commandLink | commandLink | commandLink | text | text | text

outputLink | outputLink | text | text | outputLink | text | text | text | text | text | text | icon

/pageblocktable

/pageblock

/form