We have encountered a weird bug that keep crashing App with error message "dalvikvm: JNI ERROR (app bug): local reference table overflow (max=512)". We have figured out where error was occurring but had hard time fixing. Even harder is to understand why it is happening.

It lead to some research, we have figured out it's the Crossing Bridge scenario and bug was from native Android.

The Bridge

In Titanium Appcelerator world, when your application is launched, a JavaScript execution environment is created in native code, and your application source code is evaluated. Injected into the JavaScript runtime environment of your application is what we call “proxy” objects – basically, a JavaScript object which has a paired object in native code. Colloquially we will often refer to “JavaScript land” and “native land” in a Titanium application, as they are kind of parallel universes to one another. The proxy object exists both in JavaScript land and native land, and serves as the “bridge” between the two.

Our Case

We have log trace that look like:

[ERROR] : dalvikvm: JNI ERROR (app bug): local reference table overflow (max=512)
[WARN] : dalvikvm: JNI local reference table (0xb876a4f8) dump:
[WARN] : dalvikvm: Last 10 entries (of 512):
[WARN] : dalvikvm: 511: 0xa58ab3d8 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 510: 0xa58a8518 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 509: 0xa58a5658 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 508: 0xa58a2690 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 507: 0xa58a4498 ti.modules.titanium.ui.ImageViewProxy
[WARN] : dalvikvm: 506: 0xa58a3558 ti.modules.titanium.ui.LabelProxy
[WARN] : dalvikvm: 505: 0xa57f2990 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 504: 0xa583af88 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 503: 0xa58d1948 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: 502: 0xa58ce9f0 ti.modules.titanium.ui.TableViewRowProxy
[WARN] : dalvikvm: Summary:
[WARN] : dalvikvm: 1 of java.lang.Class
[WARN] : dalvikvm: 1 of java.lang.Object[] (1 elements)
[WARN] : dalvikvm: 1 of java.lang.String
[WARN] : dalvikvm: 1 of ti.modules.titanium.network.HTTPClientProxy
[WARN] : dalvikvm: 39 of ti.modules.titanium.ui.ImageViewProxy (19 unique instances)
[WARN] : dalvikvm: 4 of org.appcelerator.titanium.proxy.ActivityProxy (1 unique instances)
[WARN] : dalvikvm: 1 of ti.modules.titanium.ui.TableViewRowProxy[] (19 elements)
[WARN] : dalvikvm: 39 of ti.modules.titanium.ui.LabelProxy (19 unique instances)
[WARN] : dalvikvm: 2 of ti.modules.titanium.ui.TableViewSectionProxy (2 unique instances)
[WARN] : dalvikvm: 423 of ti.modules.titanium.ui.TableViewRowProxy (19 unique instances)
[ERROR] : dalvikvm: Failed adding to JNI local ref table (has 512 entries)

Looking trace, we figured out that there is something wrong on TableViewRowProxy. We spotted code snipped that caused bug:

for(i = 0; i<$.tableSection.rowCount; i++){
$.tableSection.rows[i].children[1].image = "/myimage.png";
$.tableSection.rows[i].children[0].color = '#fff';
$.tableSection.rows[i].backgroundColor = '#000';
}

Crossing The Bridge

We came to know that assigning property value like above cross bridge. It creates some kind of reference at native land, which do not get destroyed automatically on native land. So the native throw error. Similar example of reference table overflow is in StackOverflow.

The Solution

var rows = $.tableSection.rows;
for(i = 0; i<$.tableSection.rowCount; i++){
rows[i].children[1].image = "/myimage.png";
rows[i].children[0].color = '#fff';
rows[i].backgroundColor = '#000';
}

Above code reduce the number of reference on native land

Crossing The Bridge - Some More Example

Take The Toll on the Kroll Bridge (2012!) by David Bankier example. He explains why it is better to just pass a model’s ID when you fire an event and then lookup the model itself up again in the listener. And 2nd example is Don’t let callbacks cross the bridge (2014) by Fokke Zandbergen. He shows that anything a callback or event listener for a Titanium proxy method will cross the bridge.