Win a copy of Head First Android this week in the Android forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Rob Spoor
  • Bear Bibeault
Saloon Keepers:
  • Jesse Silverman
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Al Hobbs
  • salvin francis

Stack

 
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
At the example below, stack exceeds its limit because each time create() method is called and it creates "my" reference in stack. But the question here is in phylosophy. After the first create(), at the second time of create() calling, WHY JVM just dont overrides the "my" reference ? As I understand, It creates so many "my" references in stack memory , this is why it exceeds its limit. If my version would be true approach, I would get an OutOfMemory error rather than stackoverflow.

Thank you.

 
Saloon Keeper
Posts: 13394
296
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In theory, the compiler could detect that the next call to create() is a so-called "tail call" and therefore the VM could discard the current stack frame before it pushes a new stack frame for the next call, thereby eliminating the chance of a stack overflow.

However, the JVM spec doesn't say that implementations must perform tail call optimization, and most don't.

Every time you call create() from within create(), it pushes a new frame on the stack. I think the JVM has a limit on how many frames can be pushed on the stack, regardless of how much data is contained inside the stack frames.

If your create() method instantiated some large arrays instead of an empty object, you would indeed run out of memory before you got a stack overflow.
 
Saloon Keeper
Posts: 1638
55
Eclipse IDE Postgres Database C++ Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, the code as written is useless, because it never returns, so it is just a quick easy pointless way to eat all your memory and have a race to see if you run out of Stack space or Heap space first on your implementation.

But the question here is in phylosophy. After the first create(), at the second time of create() calling, WHY JVM just dont overrides the "my" reference ? As I understand, It creates so many "my" references in stack memory , this is why it exceeds its limit.



If your code DID return, and did anything useful, each recursion's call to My() would be returning a distinct instance of My that would need to still be there when it got back...

Trying to understand recursion better might be served if My had a one-args constructor that represented "depth" and create() looked like:

 
Bahaddin Ahmadov
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I did what you say, but after 3639 attempts i again gives stackoverflow : even i returned value and there is logical ending :

 
Jesse Silverman
Saloon Keeper
Posts: 1638
55
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome back.

When you have a very legitimate need for very deep recursive calls there are ways to extend the amount of memory that will be dedicated to the stack.

This is not within scope for the exam you are preparing for but can be important in solving various categories of large problems using recursive solutions.

We (particularly I) talked about it a bunch here:
https://coderanch.com/t/746251/java/Avoiding-Stack-overflow-recursion

Notice in that case, recursion was not an appropriate approach to the problem the original poster was trying to solve, it was neither necessary nor helpful.

I think it is important to know because there are classes of problems in computer science that are most neatly solved recursively and you might legitimately have some very large data in some cases.

If you are just trying to understand recursion enough to ace the exam for now, further investigation would be, to use a phrase I came up with in Engineering School "Barking up the wrong dog!" (the standard phrase is "Barking up the wrong tree!" but I thought that was funnier.)

99.9% of problems that you will encounter that need to be or would benefit from being solved recursively will not require you to run the JVM with special overrides for increasing maximum potential stack depth.

Additionally, they are not covered on the exam you are preparing for.

You might like to know about them to increase your depth of Java Knowledge (I do), but you are already out-of-scope for the exam.
 
Jesse Silverman
Saloon Keeper
Posts: 1638
55
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Additionally, and this is definitely in scope for the OCPJP 11, but not the Associate Certification, your use of a static variable:

static int n = 0;

Is completely unsuitable for multi-threaded code.

Depending on which exam you are taking, that may or may not be in scope -- I believe you are targeting the Associate one so that would only be on the next exam.

That static variable would be shared by all of your threads.

This is not on the exam I think you are taking, but is covered on the one after that.

Extending the maximum potential depth of your thread stacks is not covered on either one, I am almost certain.

All problems will presume you have sufficient stack depth unless there is an accidental infinite recursion that they want you to spot, rather than just a deep one.
 
Marshal
Posts: 26912
82
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I merged your stuff with the following thread. I hope that is okay by you.
 
Bahaddin Ahmadov
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Why this code makes exceed Stack limits but not Heap limits? Why Not OutOfMemoryError, but it gives StackOverFLowError?
 
Jesse Silverman
Saloon Keeper
Posts: 1638
55
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bahaddin Ahmadov wrote:Why this code makes exceed Stack limits but not Heap limits? Why Not OutOfMemoryError, but it gives StackOverFLowError?



This is a fair enough question.  You had already been warned that this is way beyond the scope of the exam you are studying for, but it is admirable to want to understand more.

First let's note that the only reason in the world someone would ever run this code is to try to find out whether they would run out of stack memory or heap memory first.
There is no useful problem in computer science or industry where you would actually need to write the code you are running.
Furthermore, by playing with the configuration options when starting up the JVM, one could force either one to happen first.
It is nothing about computer science or the Java language, but just default start-up properties of the JVM, based on normal usage for 99.999% of programs that people need to run for business, school, fun, charities, crime, etc.

On this page:
https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html

In this section (notice, this is no longer about the Java language, but a specific, very popular version of the JVM):

Extra Options for Java
The following java options are general purpose options that are specific to the Java HotSpot Virtual Machine.



You will find:

-Xmx size
Specifies the maximum size (in bytes) of the heap. This value must be a multiple of 1024 and greater than 2 MB. Append the letter k or K to indicate kilobytes, m or M to indicate megabytes, or g or G to indicate gigabytes. The default value is chosen at runtime based on system configuration. For server deployments, -Xms and -Xmx are often set to the same value. The following examples show how to set the maximum allowed size of allocated memory to 80 MB using various units:

-Xmx83886080
-Xmx81920k
-Xmx80m
The -Xmx option is equivalent to -XX:MaxHeapSize.



and:

-Xss size
Sets the thread stack size (in bytes). Append the letter k or K to indicate KB, m or M to indicate MB, or g or G to indicate GB. The default value depends on the platform:

Linux/x64 (64-bit): 1024 KB

macOS (64-bit): 1024 KB

Windows: The default value depends on virtual memory

The following examples set the thread stack size to 1024 KB in different units:

-Xss1m
-Xss1024k
-Xss1048576
This option is similar to -XX:ThreadStackSize.



You are really curious about this stuff, so let's look at those, too:

-XX:MaxHeapSize=size
Sets the maximum size (in byes) of the memory allocation pool. This value must be a multiple of 1024 and greater than 2 MB. Append the letter k or K to indicate kilobytes, m or M to indicate megabytes, or g or G to indicate gigabytes. The default value is selected at run time based on the system configuration. For server deployments, the options -XX:InitialHeapSize and -XX:MaxHeapSize are often set to the same value.

The following examples show how to set the maximum allowed size of allocated memory to 80 MB using various units:

-XX:MaxHeapSize=83886080
-XX:MaxHeapSize=81920k
-XX:MaxHeapSize=80m
The -XX:MaxHeapSize option is equivalent to -Xmx.

-XX:ThreadStackSize=size
Sets the Java thread stack size (in kilobytes). Use of a scaling suffix, such as k, results in the scaling of the kilobytes value so that -XX:ThreadStackSize=1k sets the Java thread stack size to 1024*1024 bytes or 1 megabyte. The default value depends on the platform:

Linux/x64 (64-bit): 1024 KB

macOS (64-bit): 1024 KB

Windows: The default value depends on virtual memory

The following examples show how to set the thread stack size to 1 megabyte in different units:

-XX:ThreadStackSize=1k
-XX:ThreadStackSize=1024
This option is similar to -Xss.



These things are all fascinating (no sarcasm).

So the answer is that you run out of stack space first because of the defaults set by the JVM when you run the java command.

But why did they pick those, instead of allocating 500 times more for the stack and 80 times less for the heap, you ask?

Good question.

I believe the various aspects of the memory model for the JVM are out of scope for the exam you are taking, but are an important part of Advanced Java Understanding.

There are a few kinds or categories of memory in a running JVM.  They all matter to Advanced Experts, but only two are relevant to the answer to your question.

Stack memory is used to hold stack frames for a thread.  This includes the return address of each calling method, all parameters passed to each method invocation, and space for the local variables of each method invocation.  There may be only one thread (probably two, one for garbage collection) or your program may generate dozens, hundreds or thousands of threads.  The limit is how much stack memory that any one of these threads can get, rather than the total that can be used for all threads.

In Big Data and when solving hard computer science problems using Recursion, sometimes you need to provide for Very Deep thread stacks.

This is actually very unusual, however, and in 99.99% of times someone runs a Java program anywhere, the default is just fine.

Making the default much higher would be wasteful and could hurt performance.

Most things in Java use heap memory for their allocation.  Every object you ever allocate using new MyClass() will be allocated on the heap, as well as any standard objects you create such as File(), String() and even Integer() or Double() wrapper objects.

If you have the line:
int i, j;

those live on the stack while that method call is active.

If you say:
Integer i1 = Integer.valueOf( 2021 );
Integer i2 = Integer.valueOf( 3600 );


The values will be created on the heap, the references to them will live on the stack.
When that method completes, both i1 and i2 will immediately be removed from the stack and they will be out of scope.

If the values that they pointed to have no other references, some future garbage collection may collect the heap memory that is now unreferenced by any still-active thread.
It may happen soon, it may take a long time, or in some cases, it may never happen.

The normal usage pattern of an overwhelmingly vast majority of all Java programs written requires far more heap memory than stack space.

For the very small number of programs that require a whole lotta stack space, you can use the Advanced Options you learned about above to increase that.

If you manage to come up with a useful program that actually needs that much stack space to execute, you can report about it here on this thread.

Note: problems for interview and competitive programming platforms such as HackerRank, LeetCode and their competitors generally do NOT allow you to change the default parameters with which the JVM is invoked.  So beware of coming up with approaches that require this for their execution when engaging in such contests.  It will work on your own computer, but if you need to submit your code to their platform for auto-execution, you will run out of stack space and die, and get no points.

 
Jesse Silverman
Saloon Keeper
Posts: 1638
55
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Another way to answer that question (well, everything I said above was completely true, but)...

In what case would this crazy program (that nobody would ever run) would run out of heap space first, causing an OutOfMemoryError??

Here's one way to change it, (but still to be useless) where I would guarantee you will run out of heap space first, before ever running out of stack space:

jshell> public class My {
  ...>      String[] bigFatArray;
  ...>         public My() {
  ...>                 bigFatArray = new String[987_654_321];
  ...>                 new My();
  ...>         }
  ...>
  ...>         public static void main(String args[]) {
  ...>                  new My();
  ...>         }
  ...>
  ...> }
|  replaced class My

jshell> My kaboom = new My()
|  Exception java.lang.OutOfMemoryError: Java heap space
|        at My.<init> (#2:4)
|        at My.<init> (#2:4)
|        at My.<init> (#2:4)
|        at (#3:1)


It is good that you are curious.  In addition to the people who make Java and the JVM, every large Java shop needs some people that understand how everything is working "beneath the hood" more than any of the other programmers, who are all thinking about Banking, Insurance, Betting on Sports, or delivering diapers and baby clothes.
The defaults are set so that those other people can spend the most time thinking about those things, due to characteristics that others have studied about how memory gets used in real programs and so that most people never need to change the defaults.

These things are generally not on the exams, but the following detail may be:
The heap space is shared by ALL running threads of your program.  If you manage to run out of heap space they are all dead.  Good night Irene, Sayanora, we are out of here.

The limits on stack space are PER thread.  I don't recall, but I believe that just the thread that ran out of stack space is toast, and depending on how you have written your multi-threaded program, the other threads may be able to safely continue.  Or not.

Even this isn't on the associate exam, but I believe it may be in scope for the 819 exam.

I hope this has addressed your concerns for now.

If you actually find this very interesting, you can read the JVM specifications some time.  Most programmers will ignore it, but there are many advanced jobs you could do if you actually knew it, as most people are more interested in the applications programming side:
https://docs.oracle.com/javase/specs/jvms/se17/html/index.html

It is not on your exams.  Most Java programmers ignore it almost completely their whole lives.
But not one line of Java code ever executes without it.

If you come from an engineering background, you might find it fascinating.
Also, the JVM specifications apply not just to Java, but to Scala, Kotlin, Groovy, Jython, JRuby, Clojure etc. when running on the JVM.
The JLS is all about Java per se, not any other languages that share the JVM with it.

I consult the JLS almost daily, but go many months at a time without looking at the JVM specs, because I am focused on developing Java applications these days.
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic