I'm encountering the following error:
Exception in thread "main" java.lang.StackOverflowError
at Account.draw(Account.java:47)
This is the relevant section of code:
public double draw(double c) {
if (c > 0) {
return c;
} else if (c < 0 && c > AccBalance) {
AccBalance=-c;
return AccBalance;
}
return draw(c);
}
How can I fix this?
In your code, if c == 0, or c <= AccBalance, you keep on recursing the method with the same value of c. So, it will go into an infinite recursion, thus filling up the stack.
For each method invocation, a stack frame is allocated from the stack. Thus your code will end up allocating complete stack memory.
So, for e.g, if you call this method first time with c = 0, this is how the stack grows:
draw(0)
draw(0)
draw(0)
draw(0)
.. so on
You keep on passing 0 as argument, which doesn't satisfy any of your base cases.
As to how to solve this, we don't really have enough context to find out what should go in place of return draw(c);. But certainly that shouldn't be there. Perhaps return draw(++c);?? But we can only guess.
See also:
Recursion: Behind the Scenes
You're continually calling the draw() method. So you call the draw() method, then it calls the draw() method, then it calls the draw() method, then it calls the draw() method, et cetera, until you have no more memory left.
Check your return statement at the end. What do you want to return in that case? Right now it just keeps calling draw() again, which is probably not what you want.
You have an infinite recursion. StackOverflowError means your call stack got too deep - too many nested functions called without completing any of them - which recursion tends to do.
Related
Based on our Crashlytics logs it seems that we're running into the following exception from time to time:
Fatal Exception: java.lang.IllegalArgumentException
Illegal initial capacity: -1
...
java.util.HashMap.<init> (HashMap.java:448)
java.util.LinkedHashMap.<init> (LinkedHashMap.java:371)
java.util.HashSet.<init> (HashSet.java:161)
java.util.LinkedHashSet.<init> (LinkedHashSet.java:146)
kotlin.collections.CollectionsKt___CollectionsKt.toSet (CollectionsKt___CollectionsKt.java:1316)
But we're not sure when it is possible that this exception is actually thrown. The relevant code for this statement looks something like this:
private val markersMap = mutableMapOf<Any, Marker>()
...
synchronized(markersMap) {
val currentMarkers = markersMap.values.toSet() //it crashes here
// performing some operation on the markers
}
Right now we're suspecting multithreading to cause the issue as the markersMap is modified in multiple places, but as the map is already initialized by default we're not really sure how it can end up in less than an empty state. We also took a look at the toSet implementation:
if (this is Collection) {
return when (size) {
0 -> emptySet()
1 -> setOf(if (this is List) this[0] else iterator().next())
else -> toCollection(LinkedHashSet<T>(mapCapacity(size)))
}
}
Based on this, we'd assume that mapCapacity(size) returns -1, but we weren't able to find the actual implementation of mapCapacity to verify when this can happen.
Does anybody know when -1 is returned here, which in turn causes the constructor to fail?
Java collections are not synchronized and if you need to access a Map or any collection from multiple threads then you are required to take care of synchonization. as stated in LinkedHashMap's header
Note that this implementation is not synchronized.If multiple threads
access a linked hash map concurrently, and at least one of the threads
modifies the map structurally, it must be synchronized externally.
My guess is that you are probably performing structural modifications(mix of put and remove) on the Map without synchronization, which can cause this issue. for example
fun main(){
val markersMap = mutableMapOf<Any, Any>()
(1..1000).forEach { markersMap.put(it, "$it") }
val t1 = Thread{
(1..1000).forEach { markersMap.remove(it)
if(markersMap.size < 0){
print("SIZE IS ${markersMap.size}")
}
}
}
val t2 = Thread{
(1..1000).forEach {
markersMap.remove(it)
if(markersMap.size < 0){
print("SIZE IS ${markersMap.size}")
}
}
}
t1.start()
t2.start()
}
On my machine this code prints SIZE IS -128, SIZE IS -127 and lot many other negative values and when I added markersMap.values.toSet() inside one of the if blocks, this happened
I've seen answers using a for loop which I understood, however I came across this code recently and I have no idea how it works.
public class learn {
public static int factorial (int N){
if (N<=1 ) return 1; // won't this mean that "1" is returned at the end all the time?
else return (N*factorial (N-1)); /* since there's no variable storing the sum
I don't get how this is working out either,
won't it just be returned and lost?*/
}
public static void main(String[] args) {
System.out.println(factorial(4));
}
}
Coming from a python background, so maybe I am misunderstanding something about returns in java... [Edit] seems like return 1 is also written in Python, so it's probably not a language issue, I just don't get how recursive functions end (I get how the process goes - it's a function that calls itself).
Here's an illustration of how I interpret this code (wrongly):
factorial(4) is called
4 is more than 1, so the else statement will run -- 4*factorial(3)
factorial(3) is called - else statement runs again -- 3*factorial(2)
factorial(2) is called -- 2*factorial(1). At this point, we have 4*3*2*1 but the fact that the code only stops at the if (N<=1) return 1 line means that 1 is returned instead of the sum right? (I'm obviously wrong because the console printed the right number - 24)
won't this mean that "1" is returned at the end all the time?
No, it will only return 1 when N is less than 1. (according to your condition if (N<=1 ) return 1;)
For all other cases, it continues recursively.
since there's no variable storing the sum
I don't get how this is working out either,
won't it just be returned and lost?
When a method returns, it exits the current method and return to the point of invocation and continue from there. For simplicity, take this scenario: methodA calls methodB, and methodB calls methodC:
public void methodA(){
print("entering method A.."); //(1)methodA invoked..
methodB(); //(2)call methodB
print("exiting method A"); //(8)exit from methodB, continue from here
}
public void methodB(){
print("entering method B.."); //(3)mthodB invoked..
methodC(); //(4)call methodC
print("exiting method B"); //(7)exit from methodC, continue from here. exit methodB
}
public void methodC(){
print("entering method C.."); //(5)methodC invoked..
print("exiting method C"); //(6)exit methodC, continue from whoever called methodC
}
You will get the outpus as follows:
entering method A..
entering method B..
entering method C..
exiting method C
exiting method B
exiting method A
If you can understand the program flow of methodA B and C. Now try to understand a method calling "itself".
//Let say N is 3..
public static void main(String[] args){
factorial(3); //(9)
}
public static int factorial (int N) //(1)N:3, (3)N:2, (5)N:1
{
if (N<=1 )
return 1; //(6)Ret 1, return and continue from whoever called me
else
return (N*factorial (N-1)); //(2), (4), (7)Ret 2*1, (8)Ret 3*2*1
}
At (6), it exits the method by returning 1 and continue from the place which called this method. The place where it was called is at (7).
At (7), it exits the method by returning N*1 (which is 2*1 = 2) and continue from the place which called this method. The place where it was called is at (8).
At (8), it exits the method by returning N*2 (which is 3*2 = 6) and continue from the place which called this method. The place where it was called is at (9) which is the main method.
The if statement only returns 1 if the parameter N equals or is smaller than 1, otherwise the else clause will be executed. In the else clause, since it returns a product of parameter N and the returning value of factorial(N-1), Java needs to wait for factorial(N-1) to return a value in order to do the multiplication and return the value. There is no need to store the value of parameter N into a field since a parameter is also a variable, just its value is passed from the method's caller.
In your code, the factorial is invoked 4 times.
I am unsure of how lambdas work in practice, and I am concerned since under certain circumstances, lambdas can result in errors such as ConcurrentModificationExceptions if you use them incorrectly, which seems to be indicative of a race condition.
Consider the code below.
private class deltaCalculator{
Double valueA;
Double valueB;
//Init delta
volatile Double valueDelta = null;
private void calculateMinimum(List<T> dataSource){
dataSource.forEach((entry -> {
valueA = entry.getA();
valueB = entry.getB();
Double dummyDelta;
dummyDelta = Math.abs(valueA - valueB);
if(valueDelta == null){
setDelta(dummyDelta);
}else {
setDelta((valueDelta > dummyDelta) ? dummyDelta : valueDelta);
}
}));
}
private void setDelta(Double d){
this.valueDelta = d;
}
}
How does the forEach loop operate? Do different calls get passed to different threads where the JVM considers it appropriate, opening up the possibility of a race condition that could lead to incorrect minimum calculation?
If not, why can a forEach lambda throw a ConcurrentModificationException?
You'll get a ConcurrentModificationException if you try to modify the collection that you're iterating over while the for each loop runs. This could be done in a separate thread entirely, but much more commonly occurs when you try to modify the collection in the loop body.
Do different calls get passed to different threads where the JVM considers it appropriate, opening up the possibility of a race condition that could lead to incorrect minimum calculation?
No. No multithreading is taking place in your example above.
I have a program which can be defined as something like this
reset() {
//sets all variables to initial values
//clears all arrays
method1();
}
method1 (){
//doSomeStuff;
method2();
}
method2(){
//doStuff
method3();
}
method3(){
//doStuff
if (jobDone) reset(); //here the cycle closes
else method2();
}
All these methods are quite calculations heavy.
Depending on the input data and the result the program may do just a couple of cycles and throw a 'stack overflow' error.
I have changed the VM flag -Xss (-Xss8M) but this doesn't really solve the problem.
Is there any way to make it working almost infinitely?
Solution previously mentioned by Luiggi Mendoza: How to avoid stack overflow error
When you call reset, it calls method1, it calls method2, it calls method3 and it calls either reset or method2 both causing infinite cycle in recursion.
You probably want:
if (jobDone) return; // here the cycle realy closes
instead of
if (jobDone) reset(); //here the do _not_ close
In case you realy want infinite cycling of your code this will not cause SO due to method calling of reset or methodi:
// assuming jobDone is actually a method, you might need this variable
boolean startReset = true;
while (true) {
if (startReset) {
//sets all variables to initial values
//clears all arrays
//doSomeStuff from method1;
}
//doStuff from method2
//doStuff
startReset = jobDone;
}
}
I've been trying to optimize some of my code, and ive reached a strange conclusion regarding fors.
In my testcase ive created a new project with main activity. The activity initializes a List of 500 objects, runs an explicit GC and starts the thread. The thread loops the function doCalculations.
this.objects is a list of 500 MyObject, previous is MyObject, value is int. The function logics hold no logic, they are just there to do stuff. The difference is in the inner for.
function1
public void doCalculations()
{
for(MyObject o : this.objects)
for(int i=0; i<this.objects.size(); i++)
if(this.objects.get(i) == o)
o.value = this.objects.get(i).value;
}
function 2
public void doCalculations()
{
for(MyObject o : this.objects)
for(MyObject o2 : this.objects)
if(o2 == o)
o.value = o2.value;
}
With function 2 GC is called every ~10 secs on my nexus s, freeing ~1.7MB.
With function 1 GC is never to be seen.
Why is that?
One creates an iterator, the other doesn't.
Is the GC actually a bottleneck in your application? (It seems unlikely. Many devs, myself included, would consider the readability benefit to outweigh a few microseconds of GC.)
That said, your entire loop is a no-op anyway.
My suggestion is that' because the inner for-loop creates an Iterator for each run of the outer for loop (in function 2).
This Iterator-instances are not created in function 1