Almost all the OOM exceptions I observe so far were caused by improper written application with memory leak or third party components.
Basically, A 32 bit process has 2GB (at most 3GB if OS supports) user mode virtual address space to use. No matter how much physical memory or paging file you have, the 2GB size won't be affected. When the address space is used up (e.g. when the application tries to allocate the memory but cannot find a continuous block of address space large enough to satisfy the allocation request), OutOfMemoryException will be thrown.
OOM exceptions are usually caused by memory leak. For example, the developer allocates memory but forgets to free it after using it. For .Net applications, if we create a large number of objects and keep references to them (like adding event handlers to a WinForm control repeatedly but never removing them), garbage collection will not be able to reclaim them. Hence memory leak occurs.
Occasionally, OOM exception can also be a results of COM call. If the called method return a HRESULT 8007000e (E_OUTOFMEMORY), it can also be translated to OOM exception in .Net.
To diagnostic OOM, we need a sample to reproduce the problem. If that is not possible, we need to collect memory dump (usually at least several hundred MBs each dump) when problem occurs, which is not suitable on forum. I would recommend that you can have a look at
the CLR profiler. It shows you how to use the CLR Profiler tool to investigate your application's memory allocation profile. You can use CLR Profiler to identify code that causes memory problems, such as memory leaks and excessive or inefficient garbage collection.
Please remember to mark the replies as answers if they help and unmark them if they provide no help.