It is important to note that the unreasonable use of recursive calls in Java can cause stack memory to overflow.
Java will maintain a stack for each thread, and the stack will hold a stack frame for each method, and the stack frame represents the running state of a method. Which is what we often call the stack of methods. The last one is the stack frame that is currently running.
Then each method call will generate a stack frame for the new calling method, save the stack frame state of the current method, switch the stack frame context, and switch to the latest method stack frame.
When choosing between recursion and looping, it is preferable to choose loops rather than recursion, especially to avoid depth recursion.
The need to know about recursive return is the tail recursive call, and the tail recursive call can be optimized.
A tail call refers to the invocation of a method or function in the last instruction of another method or function. The following defines a Foo () function as an example:
int foo (int a) { = a + 1; return func (a);
The tail call, not just the tail recursion, the function call itself can be optimized out, and become the same as the goto operation. This means that the stack is set before the function call, and the operation to recover the stack after the call is completed (Prolog and Epilog, respectively) can be optimized.
Developers of functional languages often use recursion, so the interpreter for most functional languages is optimized for tail calls. But using depth recursion in Java must be very careful, otherwise it is likely to cause stack overflow to occur.
Here is an example of an unreasonable use of recursion:
Packagetest; Public classRecursivetest {/*** Recursive Implementation * *@paramN *@return */ Public Static DoubleRecursiveLongN) {if(n = = 1) { returnMath.log (1); } Else { returnMath.log (n) + recursive (n-1); } } /*** Non-recursive implementation * *@paramN *@return */ Public Static DoubleDirectlyLongN) {Doubleresult = 0; for(inti = 1; I <= N; i++) {result+=Math.log (i); } returnresult; } Public Static voidMain (string[] args) {inti = 5000000; LongTest =System.nanotime (); LongStart1 =System.nanotime (); DoubleR1 =recursive (i); LongEnd1 =System.nanotime (); LongStart2 =System.nanotime (); Doubler2 =directly (i); LongEnd2 =System.nanotime (); System.out.println ("Recursive result:" +R1); System.out.println ("Recursive time used:" + (End1-Start1)); System.out.println ("Non-recursive Result:" +R2); System.out.println ("Non-recursive time used:" + (End2-start2)); }}
Other reasons why a memory overflow may occur in the JVM include:
- Too many reference variables use static modifiers such as public STAITC Student s; it is best to use static adornments in properties in a class with only the base type or string. such as public static int i = 0; public static String str;
- Use a large number of recursive or infinite recursion (recursive using a large number of new objects built)
- Use a large number of loops or dead loops (a large number of new objects are used in the loop)
- Whether to use a method that queries all records to the database. That is, a one-time full query method, if the amount of data more than 100,000, it can cause memory overflow. Therefore, a "paged query" should be used when querying.
- Whether there is an array, the LIST,MAP is a reference to an object, not an object, because these references cause the corresponding object to not be freed. are stored in memory in large quantities.
- Whether to use the "non-literal string for +" operation. Because the contents of the string class are immutable, a new object is generated each time the "+" is run, and if too many new string objects are created, a memory overflow occurs that causes the JVM not to be reclaimed in a timely manner.
such as String S1 = "My name";
String s2 = "is";
String s3 = "Xuwei";
String str = s1 + s2 + s3 + ...; This can easily cause memory overflow.
Recursive invocation in Java