We have an umbraco 4.11 instance with around 400 nodes, running on iis 7.5, .net 4, windows 2008 r2. upon first visit it consumes around 500mb of ram and moves up to around 900mb. Since the site is going to be deployed on a shared hosting, this would cause us massive problem.
I've tried tracing the custom codes for memory leaks, and found nothing. I Also ran Windbg on the app pool memory dump only to find the following report:
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 461 7fb`9ab99000 ( 7.983 Tb) 99.79%
<unknown> 1201 4`4ec32000 ( 17.231 Gb) 98.00% 0.21%
Image 2604 0`1123e000 ( 274.242 Mb) 1.52% 0.00%
Heap 74 0`037c2000 ( 55.758 Mb) 0.31% 0.00%
Stack 172 0`01c00000 ( 28.000 Mb) 0.16% 0.00%
Other 9 0`001b2000 ( 1.695 Mb) 0.01% 0.00%
TEB 57 0`00072000 ( 456.000 kb) 0.00% 0.00%
PEB 1 0`00001000 ( 4.000 kb) 0.00% 0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 628 4`50cda000 ( 17.263 Gb) 98.18% 0.21%
MEM_IMAGE 3453 0`135fc000 ( 309.984 Mb) 1.72% 0.00%
MEM_MAPPED 37 0`01181000 ( 17.504 Mb) 0.10% 0.00%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 461 7fb`9ab99000 ( 7.983 Tb) 99.79%
MEM_RESERVE 985 4`226fb000 ( 16.538 Gb) 94.06% 0.20%
MEM_COMMIT 3133 0`42d5c000 ( 1.044 Gb) 5.94% 0.01%
--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 881 0`2edd3000 ( 749.824 Mb) 4.16% 0.01%
PAGE_EXECUTE_READ 406 0`0f016000 ( 240.086 Mb) 1.33% 0.00%
PAGE_READONLY 1157 0`02c1a000 ( 44.102 Mb) 0.24% 0.00%
PAGE_WRITECOPY 422 0`01cde000 ( 28.867 Mb) 0.16% 0.00%
PAGE_EXECUTE_READWRITE 121 0`00328000 ( 3.156 Mb) 0.02% 0.00%
PAGE_EXECUTE_WRITECOPY 89 0`0026e000 ( 2.430 Mb) 0.01% 0.00%
PAGE_READWRITE|PAGE_GUARD 57 0`000e5000 ( 916.000 kb) 0.00% 0.00%
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free 5`3f530000 7f9`54ca0000 ( 7.974 Tb)
<unknown> 2`835b4000 0`7bf7c000 ( 1.937 Gb)
Image 7fe`e79da000 0`01338000 ( 19.219 Mb)
Heap 0`0c5e0000 0`00961000 ( 9.379 Mb)
Stack 0`00960000 0`0007b000 ( 492.000 kb)
Other 0`006b0000 0`00181000 ( 1.504 Mb)
TEB 7ff`ffe90000 0`00002000 ( 8.000 kb)
PEB 7ff`fffdb000 0`00001000 ( 4.000 kb)
the other reports about managed portions of memory are ommitted because they don't show anything out of the ordinary. the dump shows that region or the unmanaged portion is consuming the most memory, which is an indication of win32 api calls or something else I don't know about. What I need to know is if this memory usage is usual? if not what are the causes and fixes that can be applied on it? I'd appreciate any help to clear this issue! 0
As Eric Herlitz points out in his answer there are many things going on under the hood of an Umbraco installation. In a nutshell, 400 nodes shouldn't cause too much of an issue, as they are published as XML and then cached. Also, a standard Umbraco installation isn't that resource hungry, so there is almost certainly something else at play, and probably quite basic. So check the following:
How are you accessing node content? The most basic mistake that can be made is using the Umbraco API to access node content when you don't need to. For read-only scenarios where you only need published data (e.g. displaying content in the published website) you should use the methods that query the published data in the XML cache. In 4.11.x this would be the umbraco.NodeFactory.Node
, INode
or DynamicNode
via the DynamicNodeContext
model passed to a macro. You should avoid using the Document
, Content
objects etc. as these make calls to the database.
How are you accessing media? Since 4.8, all media saved in the CMS is indexed in the same way nodes are. In 4.7, you would use new Media(id)
to retrieve a file in the media library. This hits the database and is therefore very expensive per request. You should use new DynamicMedia(id)
as this retrieves the file information from the index and is very quick and makes a substantial difference.
Are you caching macros? Careful use of this feature can help massively. Even calls to the XML cache have a footprint and things like rendering the main navigation of a site can be quite expensive. I tend to cache complex navigation macros like this that are repeated throughout the site. Yes, the will still cause a hit on first request, but they won't subsequently. If you have limited resources however, don't go nuts with the macro caching. Be selective and consider which pages get the most traffic and which have the more complex node traversal queries.
What data are you storing in your document types? You shouldn't really have to review this but it's worth a check especially if you are concious of your site growing in size. If you use the multi-node picker, do you store the XML or the CSV? The CSV is substantially smaller as it only stores the IDs of the nodes. Storing XML is useful for structured data and for accessing using XSLT, but redundant if you are only pulling out the ID of media or content nodes. Do you also have additional fields that aren't used? These will get published to the XML and can save you resources as the XML grows. More fields also means more trips to the database when nodes are saved and published. So less is better.
Are you storing data that doesn't need to be? There is a tendency to make everything CMS-editable. A LinkedIn URL, Twitter ID, company phone number, payment gateway callback pages etc. But realistically, things like this don't change very often if at all. These can safely be relegated to keys in the AppSettings module of the web.config file. And then accessed via static "ConfigConstants" class that makes the keys read-only. This saves a bit of space in the XML cache and lightens the load of saving and publishing pages. It also means that you don't have to query the XML cache for the data.
Do you have an intermediary querying layer and/or extension methods? This is by no means necessary but I like to have extension methods that prevent repetition of code use through the UI. This means that I can always be sure that when I query for a media item, boolean property, root node, etc. I am using the same code each time. I can also perform a little extra caching at this point. So if I had a "Site Settings" node, I could cache the properties of this in an custom lightweight object, so that I didn't have to query for the "Site Settings" node and then its properties each time I needed to access the site-wide data like an address, phone number, URL etc.
Hope this helps a little.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With