views:

328

answers:

6

I have a loop that spawns a lot of threads. These threads contains, among other things, 2 (massive) StringBuilder objects. These threads then run and do their thing.

However, I noticed that after a certain amount of threads, I get strange crashes. I know this is because of these StringBuilder, because when I reduce their initial capacity, I can start a lot more threads. Now for these StringBuilders, they are create like this in the constructor of the thread object:

StringBuilder a = new StringBuilder(30000);
StringBuilder b = new StringBuilder(30000);

The point where it generally crashes is around 550 threads, which results in a little bit more than 62MB. Combined with the rest of the program the memory in use is most likely 64MB, which I read online somewhere was the defaulf size of the JVM memory allocation pool. I don't know whether this is true or not.

Now, is there something I am doing wrong, that somehow because of the design, I am allocating memory the wrong way? Or is this the only way and should I tell the JVM to increase its memory pool? Or something else entirely?

Also, please do not tell me to set a lower capacity, I know these StringBuilders automatically increase their capacity when needed, but I would like to have a solution to this problem.

+5  A: 

Use the -Xmx JVM option to increase the Java maximum heap size.

Before J2SE 5.0, the default maximum heap size was 64MB. You can override this default using the -Xmx command-line option.

Gregory Pakosz
and no I don't even want to know why those 500+ threads are allocating those monster StringBuilders :p
Gregory Pakosz
+2  A: 

If you are storing a lot of information in a StringBuilder, are you going to reference back to it at some point? If not then just write it to another medium (DB, File etc). The program has a finite amount of resources, it can't hold all of the state of an entire system at once. -Xmx will give you more space for storage in the memory, however it won't make your storage ability infinite.

monksy
+1  A: 

Assume 1MB per thread. That's the RAM cost of creating each one, over and above the memory allocated by its process.

duffymo
Isn't this platform dependent? I may be wrong but I think it is (and can be tuned using the `-XX:ThreadStackSize=size` option, see http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp).
Pascal Thivent
Might be, Pascal. I was citing a rough rule of thumb, not a precise value as you've just done. Thanks for the citation.
duffymo
+1  A: 

As Gregory said, give the jvm, some options like -Xmx.

Also consider using a ThreadPool or Executor to ensure that only a given amount of threads are running simultaneously. That way the amount of memory can be kept limited without slowdown (as your processor is not capable of running 550 threads at the same time anyway).

And when you're using an Executor don't create the StringBuilders in the constructor, but in the run method.

extraneon
+2  A: 

Consider using a ThreadPoolExecutor, and set the pool size to the number of CPUs on your machine. Creating more threads than CPUs is just adding overhead.

ExecutorService service = Executors.newFixedThreadPool(cpuCount))

Also, you can reduce memory usage by writing your strings to files instead of keeping them in-memory with StringBuilders.

Sam Barnum
A: 

You can use a FileWriter to output text to a file, then pull it back in with a FileReader. That way you'll only need to store the filename in memory, rather then the entire contents of the string.

To cut down on threads you can use an ExecutorService, or simply use a few threads that read out of a queue.

My guess is that with a little tinkering you can probably get your program down to not needing much memory at all.

Chad Okere