There's probably a number of factors here. arrayString
is going to need 300MB of memeory. If that's larger than your maximum memory size, that's your problem right there. If your minimum size is smaller, that will slow down the garbage collector as it tries to get the memory that it really does need.
Next, you are repeatedly creating a StringBuilder instance needing roughly 50KB. This space might or might not get recycled efficiently, but it usually takes time for the GC to fully recover larger spaces. So you can be using only 50% or less of the max memory and yet the GC is taking forever to truly free any space. (Not that 50KB is all that large compared to 300MB, but I thought I'd mention it.)
The last problem is that if the GC starts taking too long, it just gives up and throws an OutOfMemoryError. This can happen even when plenty of memory is theoretically available.
The simplest fix is to give it lots more minimum and maximum memory. Don't think that because you're not using the maximum you're safe from an OOM.
It's also worth noting that the rapidity of allocating and freeing memory hurts you. Interleaving some code that makes fewer demands (fewer new
's and smaller sizes) can give the GC more time to organize memory. With longer deadlines, the GC won't get so far behind despite the needed work being the same, and hence it won't give up and throw the OOM.
The people who write GCs are always tweaking them and trying for better tradeoffs, so it's a bit tricky to say exactly what the GCs are doing, or what they'll be doing tomorrow. Here, I'm just trying to give you a few ideas.