Here is an excellent article on types of memory leaks you can still have in a managed app: http://msdn.microsoft.com/msdnmag/issues/07/01/ManagedLeaks/default.aspx.
One thing I was blown away with was this code snippet that dynamically creates an assembly in memory:
CodeCompileUnit program = new CodeCompileUnit();
CodeNamespace ns = new
CodeNamespace("MsdnMag.MemoryLeaks.CodeGen.CodeDomGenerated");
ns.Imports.Add(new CodeNamespaceImport("System"));
program.Namespaces.Add(ns);
CodeTypeDeclaration class1 = new CodeTypeDeclaration("CodeDomHello");
ns.Types.Add(class1);
CodeEntryPointMethod start = new CodeEntryPointMethod();
start.ReturnType = new CodeTypeReference(typeof(void));
CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Console"), "WriteLine",
new CodePrimitiveExpression("Hello, World!"));
start.Statements.Add(cs1);
class1.Members.Add(start);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults results = provider.CompileAssemblyFromDom(
new CompilerParameters(), program);
(Beware of dynamically generating MSIL using System.CodeDom like this. If you are regenerating code then you are leaking unmanaged heap memory.)