Is it still the case that Android never unloads classes? - android

We have a large app that's always running into the dread method count limit. I've been asked to come up with a way to let it do much more, including supporting plugins. Looking for ways to unload code, I ran across JNI Tips which says
Classes are only unloaded if all classes associated with a ClassLoader
can be garbage collected, which is rare but will not be impossible in
Android.
This did seem to imply that a plugin can be unloaded if you, say,
use a new DexClassLoader for each .jar file,
only ever refer to the plugin through an interface reference, and
null-out any copies of that interface reference when done.
So, I created a test case:
I created a couple of trivial plugins, using a unique loader for each.
I created a ReferenceQueue<ClassLoader> and created weak references to my two loaders, using that queue; I created/started a thread that loops indefinitely, doing a queue .remove() and reporting.
I similarly created a ReferenceQueue<Class<?>> and created weak references to each plugin's getClass() using the queue; I created/started another thread monitoring the class reference queue.
I create a thousand 1000x1000xARGB_8888 bitmaps to thoroughly force gc.
My monitoring threads seem to work - I saw loader2 get gc-ed when I used loader1 to load both plugins by mistake ;-) - but otherwise my threads stay silent, even on 4.3. Am I maybe missing something obvious in this test case, or is it still the case that the
Dalvik VM doesn't currently unload classes
as Google employee fadden says in Android: When do classes get unloaded by the system?

The Dalvik VM still doesn't unload classes. The JNI Tips page is encouraging good behavior so your app doesn't break if the VM starts unloading classes someday.

Related

Is memcpy() / mktime() thread-safe on iOS & Android?

I have a C library which I'm cross-compiling to use in Android & iOS apps.
It makes use of memcpy() and mktime() so I want to know if these functions are implicitly thread-safe when used in multi-threaded environments.
iOS apps compiled with modern Xcode and Android libraries compiled with modern Android NDK use a clang compiler which is LLVM-based.
I've reviewed the following questions, but have been unable to find a definitive answer:
Is memcpy process-safe?
Are functions in the C standard library thread safe?
POSIX requires of conforming implementations that all functions it standardizes be thread safe, with the exception of a relatively short list of functions. memcpy() and mktime() are both covered by POSIX, and neither is on the list of exceptions, so POSIX requires them to be thread safe (but read on).
Note well, however, that this is not a matter of the compiler used, but rather of the C library that supports your application. I recall Apple's C libraries being non-conforming in some areas. Nevertheless, there's nothing in particular about memcpy() and mktime() that makes them inherently risky from a thread safety perspective. That is, there's no reason to expect that they access any shared data, except any provided to them via their arguments.
And there's the rub. You can rely on memcpy() and mktime() not to, say, rely internally on static data, but POSIX's requirement for thread safety does not extend to working as documented in the face of data races you create through choice of arguments. Thus, for example, if two different threads call memcpy(), and the target region of one call overlaps either the source or target region of the other, then you need some flavor of synchronization between the threads.
The question if memcpy() is thread-safe might be discussible.
I would say that memcpy() is indeed thread-safe. It doesn't rely on a (global) state, which could be mangled up by multiple instances of memcpy() running. This, however, doesn't mean, that there is some magic preventing a memory area, which is concurrently the copy destination of multiple threads doing memcpy() gets badly mangled up, i.e. the copy process as a whole is not atomic. You would have to care yourself using mutexes to ensure atomicity.
mktime() is trivially threadsafe, since it doesn't use static buffers, use a global state or similar. The manpage mentions a few functions from that family being not threadsafe (those have corresponding *_r functions), but mktime() is not amongst those.

Why is there a separate instance of VM(Dalvik/ART) for every App on Android?

As the title states,
Why is there a separate instance of VM(Dalvik/ART) for every App on Android?(the need for it)
and, what would have happened if the Android OS had chosen a model where a single VM runs all the apps?
There are many reasons why running multiple applications in a single process doesn't work; here's two:
Security zones.
Two applications that don't trust one another shouldn't be able to view each other's memory, even if they use native code or reflection.
Failure isolation.
If a process leaks memory and crashes, it harms only itself.
Why there is a separate instance of VM(Dalvik/ART) for every App?(the
need for it)
It is a design decision, and in my opinion, is made to keep it simple. Every process runs in its own vm. All the resources are allocated to that process, and the vm, internally, has not to coordinate access to resources, e.g. FileDescriptors, I/O etc. I never heard of multiprocess vm (a vm that allows more than one process to run in it), but I found an article that you could give you an insight.

What's happenings if I don't implement the override methods in Android?

I'm developing an Android app, and I already read about the lifecycle of an activity.
I don't know, what's happens if I don't implement the methods of the lifecycle onCreate(), onDestroy(), etc..
The JVM calls automatically these methods?
I'm habitual in iOS, and the change to Java is some peculiar for me. I want call the methods to manage memory.
I'm supponing that these methods helps to manage the memory in my App and this not crash in runtime.
The Android framework always calls those methods. If you don't implement them, the base class methods will be run. Typically they do nothing (significant). However, you definitely need to override some of the methods (at least onCreate) to make your activity useful.
As far as memory management goes, you usually should not worry about that at all. Java has automatic garbage collection that works very well. Unlike Objective C, in Java there is actually no mechanism for manual memory management; it's always done by the JVM. The only thing you need to pay attention to as far as memory management goes is to be sure you don't maintain hard references to large data structures that you no longer need. See the article Avoiding Memory Leaks in the Android blog.
If a method isn't overridden its base class implementation will be used.

What special powers does ashmem have?

Can someone explain why ashmem was created?
I'm browsing through mm/ashmem.c right now. As near as I can tell, the kernel is thinking of ashmem as file-backed memory that can be mmap'd. But then, why go to the trouble of implementing ashmem? It seems like the same functionality could be achieved by mounting a RAM fs and then using filemap/mmap to share memory.
I'm sure that ashmem can do more fancy stuff -- from looking at the code, it seems to have something to do with pinning/unpinning pages?
Ashmem allows processes which are not related by ancestry to share memory maps by name, which are cleaned up automatically.
Plain old anonymous mmaps and System V shared memory lack some of these requirements.
System V shared memory segments stick around when no longer referenced by running programs (which is sometimes a feature, sometimes a nuisance).
Anonymous shared mmaps can be passed from a parent to child processes, which is inflexible since sometimes you want processes not related that way to share memory.
Can someone explain why ashmem was created?
David Turner (a regular on Android NDK) answered this in Why was bionic/libc/include/sys/shm.h removed?:
... System V IPCs have been removed for cupcake. See
bionic/libc/docs/SYSV-IPC.TXT for details.
In brief, System V IPCs are leaky by design and do not play well in
Android's runtime environment where killing processes to make room for
other ones is just normal and very common. The end result is that any
code that relies on these IPCs could end up filling up the kernel's
internal table of SysV IPC keys, something that can only safely be
resolved by a reboot.
We want to provide alternative mechanism in the future that don't have
the same problems. One thing we provide at the moment is ashmem, which
was designed specifically for Android to avoid that kind of problem
(though it's not as well documented as it should). We probably need
something similar for semaphores and/or message queues.

Native C++ library - who have to release the memory and how?

This is about Android. The situation:
C++ library and java wrapper classes plus native functions (JNI) for working with C++ classes from the library. When common java code needs C++ object, it creates corresponding java wrapper object which creates C++ object through native function and remembers the pointer to the native object in 'long' variable. In all next actions the wrapper gives this pointer to the native functions etc.
The problem:
How to release all allocated C++ objects at the end? Currently every wrapper class has 'finalize' method where it calls native function for releasing of the C++ object, but Android doesn't guarantee the calling of 'finalize'! At the other side, normally the C++ library has no idea how many and what types of C++ objects are allocated by java code.
What will happens with the remaining allocated memory when our java application terminates, will Android release automatically the whole heap, used from the native library, when the OS unloads the library?
At the end of the process lifetime, all process memory (both Java and C++ heap) will be freed and reclaimed by the system. One thing is though, Android activity closing does not necessarily end the process. I'm not sure what's the process shutdown policy there.
On the other hand, relying on the garbage collection and finalize() sounds like solid design to me. You claim - "Android does not guarantee finalize()". Do you have a cite for that? 'Cause if it comes with a disclaimer of "when the object is freed as a part of process shutdown...", then we're still good.
And if you're super-paranoid, you can write your own malloc()/free()/realloc() wrapper, store a list of all allocated objects, and introduce a cleanup function that walks the list and frees them all. The containing Java objects, however, might end in a weird zombie state where the memory has been freed from under them. This is a tricky proposition that is very easy to get wrong. So I'd still say - have faith in the garbage collector. Lack thereof would be... disturbing.
Due to the difference in paradigms, you have to incorporate explicit destruction into your Java objects that are implemented under the hood using C++ resources. So a close() or other such method. The same issue comes up with the JNI, so answers to those questions will apply to you:
Force Java to call my C++ destructor (JNI)
As for the memory issue on closing, it's generally best in my opinion to not rely on this. If you get to a clean state, valgrind and such can make sure you weren't leaking.
But from a technical standpoint--since Android is based on Linux, I'd imagine it does the usual thing and will free all the memory when the process closes. Taking advantage of that can make your program exit faster than explicitly freeing memory (for experts only who use other methods to ensure this maintains program correctness and they aren't leaking at runtime).
We are using JNIs and we had a problem like that
Actually, the problem resided in the fact that we were overloading finalize() to do the clean up. We solved our problems by removing our finalize() and creating a clean() instead. This clean() calls the JNI function that does the appropriate deletes (and set the C++ pointers to null, just in case). We call clean() just as you would in C++ with delete (e.g. when the variable goes out of scope).
That worked for us. I hope it works for you. Good luck!

Categories

Resources