3

As we known, JNI is a bridge between Java and C++. Recently i'm coding for a Java project and it's main module is based on C++ which need to store a large number of GlobalReference. And it will increase along with activity being opened. Therefore the maximum number (65535) of GlobalReferences become a serious problem and i have to solve the problem using peculiar method.

So i'm interested in why there is a limit on GlobalReferences. Is it only for detecting the memory leaks as other's saying?

YXP
  • 71
  • 8
  • If you need even a few `GlobalReferences` you already have a major problem. Reconsider. – user207421 Jul 29 '17 at 03:56
  • I'm sorry i can't catch the point EJP. The lifecycle of the `GlobalReferences` is managed by the object of C++ in my project, so i have to keep a large number of them until the activity being finished. Why it is a major problem? – YXP Jul 29 '17 at 04:26
  • 1
    It's a major problem because you've hit the limit. – user207421 Oct 02 '17 at 06:56
  • Very late to the party, but does anyone know an official resource that states the global reference limit in JNI? – Paul Omta Jul 05 '22 at 07:41
  • The 64k limit is only the Android Java VM. There is no general limit. on Android even the number of methods was once limited – Lothar Jul 08 '23 at 04:16

3 Answers3

5

It is easy to answer the question 'why'. The Global References table in Android JVM (be it Dalvik or ART) has a limited number of entries because its architects did not think somebody would need more.

They had different limitations to worry about: memory constraints, performance, stability, maintenance efforts.

But after all, this is more of a rhetorical question, and the answer to it is less relevant than practical advises. Which follow:

  • The limits on references tables in Android JVM are there to stay. Don't expect these tables to become much larger in the next Android release (but maybe some of them will).

  • Whatever happens in the future releases of Android, the current versions are here to stay. Millions of people are still using Android devices with Gingerbread, which was released in 2010 (0.6% of 2 Billion). As of today, more than 20% have Dalvik JVM on their devices.

  • If you hit or come close to the limit on the internal JVM tables, you must reconsider your architecture. You cannot trust the behavior of the system when these tables overflow, even if it does not happen every time.

  • Remember that memory available to your app is also limited, and the more you use, the more likely your app will suffer performance hit in multitasking environment: the kernel can kill it any time if it needs memory for other apps.

  • You can avoid table overflow if you aggregate your objects on the Java side. E.g. instead of keeping global references to thousands of objects, you can put them in a Java map, or array, and keep in C++ a global reference to the collection. You can manage the collection in C++ using JNI to access Map.put() and Map.remove.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Thanks for the useful advices! – YXP Oct 14 '17 at 05:26
  • 1
    It's Androids version of the 10k problem. And in networking 10k has become a 10m problem. We have 16GB phones but can only hold 65k pointers to objects or in other words 520kbyte of pointers? Thats hard at the memory limit of 640k where someone else said we will never need more than that. We already see how the restriction on methods hit the real world. – Lothar Nov 17 '20 at 02:33
2

To my understanding, it's not about detecting memory leaks really, it's about just managing memory altogether. (As for memory leaks, obviously, you shoudn't hang on to a Java object in your native code longer than you have to, global ref or not) Usage of global references is somewhat of an antipattern (when used for problems that can be solved by other means) in most languages, afaik.

Thing with JNI is that your native code is in slave mode, so to say. The JVM is unable to clean up stuff you hold on to in your C code, especially global refs ('cause their lifecycle is indefinite), so these limits are a measure to prevent developers from abusing JNI and shooting themselves in the foot.

Also, I'm a bit curious on what task you're trying to accomplish that you have to store over 65k global references -- I have a feeling that what you're trying to accomplish allows for a different approach, one that doesn't push JNI over the edge.

E.g. right now I'm wiring a native database library to an Android app, the whole setup has to throw hundreds of thousands of db records back and forth and even this case has a solution that doesn't overflow even the local ref table (512 ref limit) let alone the global ref table.

I know it's probably late, but if you care to share your actual task, we might be able to come up with a proper way of dealing with it.

Ivan Bartsov
  • 19,664
  • 7
  • 61
  • 59
  • I have solved the problem by passing `String` in activity and release all the `GlobalReferences` int the activity when pop a new activity. The actual situation is the `GlobalReferences` is kept by the C++ object so that binding the Java object to the C++ object. Briefly for each Android view there is a C++ node as controller. – YXP Oct 14 '17 at 05:41
  • Global references in JNI has absolutely nothing to do with global references in other languages. A global reference in JNI is a pointer while a global reference in other languages are global variables. It's absolutely not an antipattern. This should not be accepted answer. It's so wrong on so many things. Android/Java is can also seen as just another presentation layer. The real functionality and business logic should be in platform shared indepdentent C++ code and Java a fraction of very simple functions. Ivans wrong perspective is why we do not have good Android apps. – Lothar Nov 17 '20 at 02:23
  • One example where you need more then 65k is a text editor where paragraphs are keept as objects or a graphical editor visualizing data objects. Again, think as it as just a pointer to a GUI object (Android is nothing else then a mobile GUI on top of Linux). – Lothar Nov 17 '20 at 02:29
2

There is an obvious workaround to this limitation that i'm also have to use at the moment. Just declare an array of objects and use an index into this array.

Prefer arrays over vectors as the indirection levels are already high in Java programs. You can allocate a larger number and manager free slots in the array yourself with a few lines of trivial code.

Lothar
  • 12,537
  • 6
  • 72
  • 121