3

I have a regular 64-bit hotspot JVM which has 1 MB stack size. Now I was trying to serialize an object that has hierarchy of 3022 parents and this is giving me SO(irony) exception.

Here's some code:

while(epc.getParent()!=null){

      epc=epc.getParent();
      count++;
     }
     print(count);//3022

Above code is just to tell the hierarchy but the actual problem occurs when I try to serialize the epc object onto ObjectOutputStream.

Question, what does 1 MB stack size states in JVM as I have no idea what size a stack frame of? I'm sure it's not 1KB per stack frame because I ran about code successfully at -Xss3000k.

One more question, does every thread has 3000k stack size if I put a JVM option of -Xss3000k ?

Sachin Verma
  • 3,712
  • 10
  • 41
  • 74
  • 1
    Could you please elaborate on 'what does 1 MB stack size states in JVM' , it's not very clear. – Razvan Manolescu May 04 '16 at 11:09
  • That code does not look like it should consume a lot of stack space. How does `getParent()` work? By "serialize an object" do you mean "write it into an ObjectOutputStream"? – Thilo May 04 '16 at 11:10
  • @RazvanManolescu I wanted to know if 1 MB can process serialization of an object that has parent hierarchy of 3022 parents? – Sachin Verma May 04 '16 at 11:10
  • Possible duplicate of [How to increase the Java stack size?](http://stackoverflow.com/questions/3700459/how-to-increase-the-java-stack-size) – STaefi May 04 '16 at 11:11
  • @SachinVerma We need more details. The size of a stack frame depends on what local variables you have in your method called recursively. Additionally, you can forgo using the JVM stack and write a non-recursive method that uses a `java.util.Stack` instead of calling itself. – nanofarad May 04 '16 at 11:13
  • But, yeah, default object serialization will recurse into the object graph. So if you have 3022 parent references to follow, then you need enough stack to accomodate that. – Thilo May 04 '16 at 11:14
  • Just one question, does every thread has 3000k stack size if I put a JVM option of -Xss3000k ? – Sachin Verma May 04 '16 at 11:14
  • The JVM option sets the default stack size for a thread. Unless the thread is explicitly created with a different stack size (unlikely), they will all get this size. You may want to just create one thread for your serializer with the extra stack space. http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#Thread%28java.lang.ThreadGroup,%20java.lang.Runnable,%20java.lang.String,%20long%29 – Thilo May 04 '16 at 11:17
  • @Thilo Thanks, but I also want synchronization in my life. – Sachin Verma May 04 '16 at 11:18
  • @sachinverma protip: don't use the builtin object serializers. Java has a ton of libraries like kyro and Xstream. – Adam Gent May 04 '16 at 11:28
  • @AdamGent: But those would most likely also make use of recursion in the same way, no? – Thilo May 04 '16 at 11:42
  • @Thilo they may use recursion but you don't have to use the actual call stack for recursion (as hexafraction alluded to using a heap stack ie java.util.Stack). I have serialized very deep object graphs in the millions with no problems. I know XStream actually has some special handling for deep object graphs. I feel like I must be missing something given your rep... – Adam Gent May 04 '16 at 13:01

2 Answers2

9

Question, what does 1 MB stack size states in JVM as I have no idea what size a stack frame of?

A 1 MB default thread stack size means that every thread has 1MB (1048576 bytes) of stack space ... by default. The exception is if your code creates a thread using one of the Thread constructors where you can provide a stack size argument.

The size of a stack frame depends on the method being called. It needs to hold the method's parameters and local variables, so the frame size depends on their size. Each frame also needs (I think) two extra words to hold a saved frame pointer and a saved return address.

Note that in a recursive algorithm, you can have more than one stack frame for one "level of recursion". For writeObject (in Java 8), the algorithm used is recursive, and there are typically 4 frames per level of the data structure being serialized:

writeObject0 
writeOrdinaryObject
writeSerialData
defaultWriteFields
writeObject0
etcetera

The actual frame sizes will be platform dependent due to differences in compilers, and changes in the implementation of ObjectInputStream / ObjectOutputStream. You would better off trying to (roughly) measure the required stackspace rather than trying to predict frame sizes from first principles.

One more question, does every thread has 3000k stack size if I put a JVM option of -Xss3000k ?

Yes ... with the exception that I have described above.

One possible solution to your dilemma is create a special thread with an huge stack that you use for serialization. A similar thread with a huge stack will be required for deserialization. For the rest of the threads, the default stack size should be fine.

Other possible solutions:

  • Implement writeReplace and readResolve methods to flatten the parent structure of your epc objects into an array so that you don't get deep recursion. (Obviously, the flattening / unflattening needs to be done non-recursively.)

  • Do the same flattening before you call writeObject, etcetera.

  • Use a different serialization mechanism, or possible a custom one.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • 1
    It should be emphasized that managing to serialize an object graph via raising the stack size will require a raised stack size at the deserializing end as well and, as you correctly noted, the exact requirement will be implementation-specific. – Holger May 04 '16 at 13:29
2

Does every thread has 3000k stack size if I put a JVM option of -Xss3000k ?

There is a constructor to specify the stack size for the new Thread. All threads that don't use that special constructor will get the default stack size specified in the JVM option (and that will cover all threads unless you create them yourself explicitly).

If your application does not need a great number of threads, the raised limit is probably not a problem and the easiest solution.

If not, you may want to construct such a big-stack thread especially for running your deeply recursive serialization code. You can wrap it up into an Executor and have application code call into it.

what does 1 MB stack size states in JVM as I have no idea what size a stack frame of?

That is indeed a bit of a moving target. You should make this configurable and experimentation will tell you what a good setting is.

Even the Javadoc says

Due to the platform-dependent nature of the behavior of this constructor, extreme care should be exercised in its use. The thread stack size necessary to perform a given computation will likely vary from one JRE implementation to another. In light of this variation, careful tuning of the stack size parameter may be required, and the tuning may need to be repeated for each JRE implementation on which an application is to run.

Community
  • 1
  • 1
Thilo
  • 257,207
  • 101
  • 511
  • 656