You can't "outrun" the garbage collector, but it is possible to stress it badly. This usually shows up as high CPU usage, rather than the GC not cleaning up large chunks of memory that need to be cleaned up.
If you are building up to an OutOfMemoryException over half an hour, then it certainly isn't the case that you're overloading the garbage collector. It's much more likely, as others have said, that references to new objects you're creating are staying alive as your application runs. This doesn't mean you should just set your timer loop up to null everything out, you need to identify the cause of the retained references and what action you should be taking to tidy things up at the end of a piece of work that you're not currently doing.
The best tool for this kind of work is a memory profiler. They will analyse living objects and the references to them in your application and allow you to find out what objects you think should be collected are still alive, and why. This will be the cause of your leak.
The GC will identify what objects in your application are guaranteed to be alive (gc roots), such as static variables, local variables, etc. It will then follow what the roots reference to find every currently living object. The rest is garbage. This is a very simplified way of putting it, but it shows that what you need to find is what root path(s) lead to the objects you're creating, and break them at the appropriate point.
Although you say you are not using events yourself, it's very likely that some control that is alive the whole time is subscribing to events on your new objects, or otherwise keeping them in a list somewhere.
I have used the Scitech memory profiler a lot before and found it to be very helpful. There are also other tools - dotTrace, Ants memory profiler, and lots more. I have used a fair few of them and find that Scitech's profiler gets to the point best. They probably all have trial periods! :)