We have 5 servers, but all applications could technically be on all 5 
servers (load balancer picks a server), though they usually aren't. I know 
what you are going after, and I agree with you. There are lots of ways I 
could solve this in my own application.

The issue I have isn't necessarily about how our application is, it only 
makes it bad for us. That's not the issue I want to discuss, I merely 
brought up the details of our scenario as an example where it can cause 
issues, but those issues aren't necessarily nhibernates problems.

At it's core, the issue is do we care how much memory nhibernate uses, and 
if so, can we make it lighter.

Another idea that could possibly solve this for our usage is to use Lazy<T> 
as the storage for the strings, so that they are only generated and cached 
when they are actually used (thus speeding up start time as well). In our 
scenario, I don't really care that nhibernate is caching all this, it just 
seems a bit useless when we don't actually use a certain query, and thus 
lazy would basically solve that problem as well.



On Tuesday, May 29, 2012 1:35:05 PM UTC-6, Ayende Rahien wrote:
>
> Get another server, cheaper than the alternative
> And 15 app pools times 50 = 750 apps on a single server
>
> On Tuesday, May 29, 2012, Darren Kopp wrote:
>
>> The problem doesn't go away, the problem just thrashes the paging file. 
>>
>> We have a 64-bit server with 32-GB of memory (limit for Server 2008 Web 
>> Edition).
>> We have 15 AppPools with limit on Private Bytes at 1.8GB (about 27GB)
>>
>> Switching from 32-bit to 64-bit merely makes the problem worse as we now 
>> use more memory for every integer that we had before, but with no real 
>> benefit other than we don't hit OOM because additional usage goes into the 
>> paging file on disk which makes everything slower.
>>
>> On Tuesday, May 29, 2012 1:25:34 PM UTC-6, Ayende Rahien wrote:
>>
>> Use 64 bits, problem goes away
>>
>> On Tuesday, May 29, 2012, Darren Kopp wrote:
>>
>> A) Yes. An AppPool in IIS is really limited to about 1800MB in private 
>> bytes before you start getting into territory where the framework will 
>> start throwing out of memory exceptions. So when we have ~50 customers in 
>> an AppPool, you get 60MB * 50 = 300MB or ~ 1/6 of the total memory 
>> available to the process solely for the SessionFactory. I just fixed 
>> problem where configuration object was being kept in process which was also 
>> 60MB, thus nhibernate was sitting on about 1/3 of memory
>> B) I completely agree with you here, only issue we run into is since some 
>> clients only use parts of our system, some update statements NEVER get 
>> executed, thus there is never a need to have them in memory.
>> C) Completely agree
>>
>> On B & C I think you are taking the GC workload argument across all 
>> statements, when GC work load argument was only specifically about 
>> interning the strings like and, or, ), (, etc. Like I said, I understand 
>> why they are cached, and I completely agree with all the arguments for 
>> caching them, the only argument against them being cached is when they are 
>> not used, or are used infrequently.
>>
>> On Tuesday, May 29, 2012 12:58:59 PM UTC-6, Ayende Rahien wrote:
>>
>> A) Are you seriously having problems with tens of MB being used? How much 
>> memory do you have on the server? How much apps are running?
>> B) The reason those are cached is to _reduce_ memory usage. Otherwise, we 
>> would need to generate an Update statement on every update. That would mean 
>> that if you need to update two Users, you would have to create two update 
>> statements.
>> By caching that, we avoid using N times memory, reduce the GC work load 
>> and generally get much better performance and memory utilization.
>>
>>
>> On Tue, May 29, 2012 at 9:55 PM, Darren Kopp wrote:
>>
>> Recently I've been trying to reduce memory usage of our website, and 
>> basically found that NHibernate was the largest source of memory usage in 
>> our system, and as I dug in found some things that I considered to be 
>> issues, though I understand the rationale behind them. I thought we might 
>> have a discussion about it though and talk about some solutions. I will say 
>> that my knowledge of nhibernate's inner workings and reasons why things are 
>> is very cursory and limited to what I have discovered/guessed during this 
>> process, which is why I would like this to be a discussion.
>>
>> *Background that can be skipped but explains why this is an issue for us.
>> *
>> The way our system was originally built is that in IIS each customer has 
>> their own website (so we are not multi-tenant), and we have a few builds 
>> that the customers are on (alpha, beta, stable) that we routinely move them 
>> between. Originally we had everyone in their own AppPool (process) but that 
>> caused a lot of memory issues because each site would have it's own copy 
>> off the code dll's loaded into memory, so we combined people into groups of 
>> app domains because IIS will share assemblies that are the same between the 
>> sites which now are in separate AppDomains rather than separate processes. 
>> This works fairly well, but we are still hitting the top end of the memory 
>> for an AppPool about every hour, so that AppPool will get recycled and a 
>> new process will be spun up. This kind of sucks because it takes about 10 
>> seconds to initialize the application (yes, we serialize our nhibernate 
>> configuration).
>>
>> *The real issue*
>>
>> Now, while poking around in WinDbg, I decided to look at the size of the 
>> SessionFactory, which for our system was ~60MB. I also notice that there is 
>> about ~30MB of strings in the process, but i'm not sure how many are unique 
>> to nhibernate, but we'll just say that it's 20MB (before session factory is 
>> built, strings account for ~10MB). Now, when I look at the session factory, 
>> it looks like for every type and builds the persisters / select builders / 
>> whatever which build up SqlString instances and cache them. All of those 
>> strings are built by SqlString class and stored in the parts. The problem 
>> is, by keeping those and holding them, you can never free up that system 
>> memory. Likely this is so that those never have to be generated again, and 
>> I do see that SqlString is immutable so really it all makes sense, just 
>> there is the problem that the memory can never be fre
>>
>>

Reply via email to