Android native strong pointer vs std::shared_ptr - android

I'm referring to Refbase.h, Refbase.cpp and StrongPointer.h
In the Android implementation of strong pointer, any strong-pointer based object must inherit refbase i.e.
sp<TheClass> theObj // TheClass must inherit from class RefBase
This requirement can be seen in the code for one of sp's methods:
template<typename T> sp<T>& sp<T>::operator =(T* other) {
if (other != NULL) {
other->incStrong(this);
}
if (mPtr != NULL) {
mPtr->decStrong(this);
}
mPtr = other;
return *this;
}
In order for call to incStrong or decStrong to not fail . . . other and mPtr must have inherited RefBase
QUESTION
Why is sp implemented such that the obj that it's managing is required to be a child of RefBase? There's not even a way to enforce this requirement at compile-time or even runtime. (Well maybe if(type()...)
Std library doesn't have such a requirement
...
Upon further thought, is the answer that this provides flexibility?
If yes, how does this provide flexibility?

It saves a memory allocation. When you write:
std::shared_ptr<Foo> pFoo{new Foo(bar)};
pFoo actually has a pointer to a shared data structure (allocated on the heap), which has the reference counters, and the pointer to the actual Foo object. By making objects be derived from RefBase, you can embed the reference counts in the object itself (saving the additional memory allocation).
Interestingly, with C++11 onwards, you can avoid the additional memory allocation by using std::make_shared<Foo> which will do a single memory allocation and construct the shared data structure and the Foo object in it.
The fact there is no compile time checking of the derivation from RefBase is carelessness. m_ptr should have been declared as RefBase *m_ptr, and then operator * (etc) should have done a static_cast to T*. In fact, I would probably have made sp<T> inherit from sp_base which had the comparison operators as public, and the other functions as protected.
Edit
On second thoughts, there is quite a bit of compile time checking. If T doesn't have an incStrong member, the compilation will fail, and it almost certainly won't unless it derives from RefBase. I still think converting a T* to a RefBase* would have been a better check, but the one that is there is probably good enough.

It automatically allows you to create sp from any object implementing RefBase, while for shared pointer you can shoot yourself in the foot while trying to wrap raw pointer into shared one.
So while for shared_ptr you might need this:
http://en.cppreference.com/w/cpp/memory/enable_shared_from_this
for sp you can almost safely pass raw pointer to sp contructor.

Related

Missing Virtual Destructor Memory Effects

According to the standard, polymorphism with a missing virtual destructor leads to undefined behavior. In practice, it really leads to the destructor for the derived class not being called when the parent class is deleted. However, does it also lead to memory leaks in any common compilers/systems? I'm particularly interested in g++ on Android/Linux.
Specifically, I'm referring to whether the deletion of memory for the derived class will somehow leak. Consider:
class Base {}
class Derived {
int x;
}
If I delete a Base* to a Derived, will I leak 4 bytes? Or does the memory allocator already know how many bytes to free based on the allocation?
It certainly can do. Consider:
class A
{
public:
virtual void func() {}
};
class B : public A
{
public:
void func() { s = "Some Long String xxxxxx"; }
private:
std::string s;
// destructor of B will call `std::string` destructor.
};
A* func(bool b)
{
if (b)
return new B;
return new A;
}
...
A* a = func(true);
...
delete a;
Now, this will create a memory leak, as std::string s in the B object is not freed by A::~A - you need to call B::~B, which will only happen if the destructor is virtual.
Note that this applies to ALL compilers and all runtime systems that I'm aware of (which is all the common ones and some not so common ones).
Edit:
Based on the updated actual question: Memory de-allocation happens based on the allocated size, so if you can GUARANTEE that there NEVER is a single allocation happening because of the construction/use of the class, then it's safe to not have a virtual destructor. However, this leads to interesting issues if a "customer" of the base-class can make his/her own extension classes. Marking derived classes as final will protect against them being further derived, but if the base class is visible in a header-file that others can include, then you run the risk of someone deriving their own class from Base that does something that allocates.
So, in other words, in something like a PImpl, where the Impl class is hidden inside a source file that nobody else derives from, it's plausible to have this. For most other cases, probably a bad idea.
A missing destructor will cause undefined behavior specifically because it's implausible for the compiler to know exactly what the side effects might be.
Think of it as the cleanup side of RAII. In that case, if you manage to not clean up despite claiming that you did, side effects might be:
Leaked memory (you allocated something... when do you deallocate it now?)
Deadlocks (you locked something... when do you unlock it now?)
Sockets remaining open (you opened it sometime... but now when do you close it?)
Files remaining open (you opened it sometime... but now when do you flush it?)
Accessing invalid pointers (for example, you updated a pointer to some member... but now when do you unset it?)
Your hard drive gets erased (technically this is a valid answer for any undefined behavior)
This should cause Undefined Behaviour which means it might also cause memory leaks. In 5.3.5/3 (n4296 c++14) for delete you have:
In the first alternative (delete object), if the static type of the object to be deleted is different from its
dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the
static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete
array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

Parceling objects in android to transfer from one activity to another

Recently an interviewer asked me a very tricky question.
There are several parts of the question.
Why (question is why and not how) do you need to parcel objects while sending from one activity to another and not send directly
Answer I gave -
Parcelable gives the capability to developers to restrict object
creation which in a way makes it faster to use.
I was confused on the part, so decided to site difference between using serializable and parcelable :p (clever huuuhhh !),
http://www.developerphil.com/parcelable-vs-serializable/ used this reference.
While using Bundle, when we use String, int we do not need to parcel the data, so do you think the String/int is by default internally parcelled ?
Answer I gave -
because String/int is a primitive data-type, if we had used the
Wrapper class directly, might be possible we had to use parcelable(I
am not sure on that part)
I did not get any useful link after googling, also I or the interviewer is not quite satisfied with the answer.
If you guys can help, would be wonderful !
Why (question is why and not how) do you need to parcel objects while sending from one activity to another and not send directly
Parcelling/serializing objects isn't for speed as you had guessed.
When you're sending data between Activities, and especially between different applications (remember that Intent objects aren't only meant for communication between your own Activities, but are also for between yours and those of other apps as well), you cannot expect the sender and the receiver to have access to the same memory address spaces.
Android's documentation states that applications run in their own discrete memory spaces. Here's a quote to that effect from the docs:
Each process has its own virtual machine (VM), so an app's code runs in isolation from other apps.
So when you want to send an object myObject to some receiving Activity, you can't send its reference/pointer because the receiver won't necessarily have access to the location specified by the pointer. Instead you'll have to send some representation of myObject that the receiver can access and use -- this is why you need to marshall the data into a form that can be unmarshalled, and the easiest way to do so is to simply have the class of the object implement Serializable which lets Java do its best to convert the object into an array of bytes that can be easily sent to and unmarshalled by the receiver. But since Serializable uses reflection, this is slow.
You can use other ways that are faster to marshall the data -- one, for example, is converting the object into its JSON representation using a library like Gson and just sending it across since any JSON document can be represented as a String and easily converted back to a Java Object. Another way, which is probably faster in pretty much all cases is using the Parcelable interface which lets you specify exactly how you want to marshall the data and exactly how it should be unmarshalled. It basically gives you more control on the transmission of the object.
The tl:dr: Parcelling/Serializing etc is used because you can't send memory addresses across, so you have to send the actual data of the object and it has to be represented in some form.
While using Bundle, when we use String, int we do not need to parcel the data, so do you think the String/int is by default internally parcelled ?
How Bundle works internally is that it puts everything into a Map and parcels/unparcels the data as needed (ie when get/put is called). For putting Objects into a Bundle, the object's class needs to implement Serializable or Parcelable because it needs to tell the Bundle how it should be marshalled/unmarshalled internally.
But primitive types and Strings are simple enough and used often enough that the developer doesn't need to specify how that needs to happen and Bundle provides convenience methods for it. I can't give you a solid answer at the lowest level of how they works because a lot of the Parcel code is natively implemented and I couldn't find it online, but they must certainly be straightforward to convert to their representation in bytes.
Just to add what #uj- said, Parcelling/Serializing is needed as #uj- said it will be sent across JVMs so they need to be converted into some format so that the other party will be able to understand.
Let me take an example to explain why serializing/parcelling is needed,
you are sending data from an application written in "C++" to an application written in java, so the following are the classes,
In C++,
class Android {
public: int dataToSend; //for example purpose making field public and omitting setter/getters
}
In Java,
class Android{
public int dataToSend;
}
suppose the C++ code generates dynamic library (which will be generated by compiling using the standard C++ compiler and then linked), and Java code generates a jar (by compiling using the javac).
When the C++ application sends data (object of Android class) to the java application the way it is compiled and linked in C++ is completely different as compared to the way its compiled in java and hence java will be wondering what has this C++ application sent to me.
Hence to get rid of such problems serialisation/parcelling is needed which will make sure that both of the application know how the data is converting while transmitting through network (in case of android how it is transmitted to another activity, may be in same or different application).
And yea when we start comparing Serialisation and Parcelling, Parcelling gets the upper hand as we will be specifying the way the data must be converted when sending the data, else in the case of serialisation the object is converted to string using reflection and reflection always takes time. Hence Parcelling is faster compared to Serialisation.
For your second question,
if we consider the above example itself then we can say that String and int being primitive types (no user defined fields in them) and hence android will be able to handle the marshalling and unmarshalling of the data which will be sent.
I tried going through the code when we go on digging deeper we end up getting native code as said by #uj-.
Some extract from the android source code:
while writing the parcel:
parcel.writeInt(BUNDLE_MAGIC);
int startPos = parcel.dataPosition();
parcel.writeArrayMapInternal(mMap);
int endPos = parcel.dataPosition();
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
while reading the parcel,
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}
int offset = parcel.dataPosition();
parcel.setDataPosition(offset + length);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
p.setDataPosition(0);
mParcelledData = p;
set the magic number which will identify the start of the parcel while writing and the same will be used while we read the parcel.
Hope I answered your question.

Issue about weakreferences

I have one or two weakreferences in my program.
Just for example:
ClassX myClassX= new ClassX(); //Line 1
WeakReference<ClassX> myWeakClassX = new WeakReference<ClassX>(myClassX); //Line 2
if(myWeakClassX.get() != null) // Line 3
{
//do something with reference //Line 4
}
My question:
How is it ensured that when at line 3 myWeakClassX.get() has a valid reference to an Object, it is also valid at line 4? I can imagine that if you are really unlucky, the GC does his job exactly "between" line 3 and 4. Please bear with me, because i'm relatively new to Android/Java..
Thanks for any explanation.
In Java, first thing to understand is Garbage Collector reclaims memory from objects which are eligible for garbage collection
Question is how is the eligibility defined ?
eligibility is decided based upon which kind of references are pointing to that object.
Why we need Weak Reference ?
If you create a Strong reference to an object, the object cannot be garbage collected. Whereas, A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.
Issue here
Weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the class) that myWeakClassX.get() suddenly starts returning null.
What is the other option ?
Soft Reference
You use a SoftReference when you want the referenced object to stay alive until the host process is running low on memory. The object will not be eligible for collection until the collector needs to free memory. Loosely stated, binding a SoftReference means, "Pin the object until you can't anymore."
This way myWeakClassX.get() will not be null.
Examples of where we can use ?
In any secondary threads where you create a reference to the activity.
WeakReference weakActivity;
//In AsyncTask onPostExecute Method
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
If you can referring to an Activity context elsewhere, you can use Weak reference.
While handling bitmap resources in imageview in another thread
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If you are creating any Hashmap or any widget to hold any data, you can use Weak reference. http://developer.android.com/reference/java/util/WeakHashMap.html
Usage is unlimited. It is up to the developer to utilize it at right places.
You are correct that during line 3 and 4 the get() operation can return null, as it is supposed to do. You can always copy the reference you get from get() operation into a variable (thus making it strong again) and use it within the if block safely. Because you still have a strong reference, the object will not be garbage collected.
A simple check for null can be:
if(myWeakClassX.get() != null)
{
ClassX myref = myWeakClassX.get();
if(myref != null) {
//use it
}
}
However in-case of activities, having a strong reference does not guarantee that the activity will not be destroyed and although you have a strong reference that is valid, the activity may throw exceptions when you try to use it as it is destroyed.
Example: If you are keep reference for an activity inside some AsyncTask, the activity might get destroyed (i.e orientation change) before AsyncTask runs. And although you will have a reference to it, you will get exceptions when you try to update UI.
That is where you can create a WeakRefernce to activity inside the AsyncTask and if the get() operation start returning null, you will know that the activity was destroyed by whatever reason and not try to use it.

JNI GlobalReference (New/Delete) and java.nio.ByteBuffer what's the relationship in Android NDK context

Have been using java.nio.ByteBuffers on the NDK side for a while now - noticed this article about Android relationship with JNI, GC and future of ICS. Article here http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html
So... here is the concern:
Since the "pointer" that JNI provides seems to actually be a reference that is managed by the JNI internaly - it could be "moved" or deleted by GC at some point if it is not marked as NewGlobalReference() in JNI method before being passed to c++ classes?
In my JNI methods I take the Direct Buffer address and pass it on to classes that use it, without any
env->NewGlobalRef(jobject);
env->NewLocalRef(jobject);
env->DeleteGlobalRef(jobject);
management.
For now it all works - but is it correct?
Thoughts?
P.S - I do use free(ByteBuffer) on exit/destructor in c++
A local reference is only valid for the duration of the JNI method that it is passed to or created in. After that method returns to the JVM, the reference is no longer valid. If you're not breaking that rule, you're OK.
It's a bit unclear what you're asking, so let me try to clarify a few points.
Any jobject type you get in JNI, whether returned from a JNI call like FindClass or passed in as an argument (jobject, jclass, jbyteArray, etc), is a local reference. It has a very short lifespan. If you pass it to NewGlobalRef, you get a global reference in return; this will last until you delete it.
Any JNI function that takes or returns a pointer type is giving you a pointer that's good until something invalidates it. For example, if you call GetStringUTFChars, you get a const char* that's valid until you call ReleaseStringUTFChars.
References are not pointers, and pointers are not references. You can't pass a char* to NewGlobalRef, and you can't dereference a global reference (where "can't" is usually an error or a native crash).
What I assume you're doing is calling GetDirectByteBufferAddress on a ByteBuffer object, which returns a void* that points to the start of the direct byte buffer. This pointer is valid until the storage is freed. How that happens depends upon how you allocated it:
If you allocated the direct byte buffer with ByteBuffer.allocateDirect(), then Dalvik owns the storage. It will be freed when the ByteBuffer becomes unreachable and is garbage collected.
If you allocated the storage yourself, and associated it with a ByteBuffer with the JNI NewDirectByteBuffer call, then it's valid until you free it.
For the allocateDirect() case, it's very important that your native code stops using the pointer before your managed code discards the ByteBuffer. One way to do this would be to retain a global reference to the ByteBuffer in your native code, and invalidate your buffer pointer at the same time you delete the global reference. Depending on how your code is structured that may not be necessary.
See also the JNI Tips page.

JNI: map jobject to native c++ object

I use regular std::map to map jobject's to c++ objects. The problem with this approach is that it may fail for other types of references, e.g. global references are actually different pointer than regular local references even if they reference the same object. The correct way to compare if two references reference the same object is:
env->IsSameObject(jobj1, jobj2);
So, my question is: what's the correct way to map jobject's to c++ objects? The obvious reply to wrap jobject into some c++ class that overloads operator== and calls IsSameObject isn't the reply that I'm looking for. I'd like to know if there is way to do it without going back and forth between JVM and native c/c++ for every compare operation.
EDIT: global reference is a jni global reference, and has nothing to do with c++ references.
EDIT2: I'd like to clarify what the problem is with this code:
std::map<jobject, void *> jobjs;
jobject obj1, obj2;
... some code that sets these obj1 and obj2 to some Java objects.
jobjs[obj1] = new CppPeer;
CppPeer * = jobjs[obj1]; //OK...
if(objs.find(obj2) == objs.end()){
assert(obj2 != obj1);
//Here's the problem: here a new c++ CppPeer
//created for obj2, but the problem is that
//even if obj1 != ob2 it doesn't mean that
//they actually reference different java objects
//On the next line error might happen
jobjs[obj2] = new CppPeer; //maybe not OK here...
}
The other problem with IsSameObject is that it makes things pretty nasty and messy. Not only now I'd need to keep a pointer to JVM, but also whenever I need to compare jobjects I'd need to attach thread etc to get pointer to JNIEnv to be able to check jobject
EDIT3: Be aware, that according to android docs you cannot even assume that two references reference the same object if they are equal. I don't know how it's possible, but there's the part from Android's JNI tips page:
One consequence of this is that you must not assume object references
are constant or unique in native code. The 32-bit value representing
an object may be different from one invocation of a method to the
next, and it's possible that two different objects could have the same
32-bit value on consecutive calls. Do not use jobject values as keys.
DISCLAIMER: it smells.
On Android, pointer and jint are of the same size. Consider adding an int field to your Java class to store a pointer to the native conterpart. When in a JNI method, typecast it back to a pointer.
To be on a slightly safer side, do a static assert on datatype matching:
{char a[sizeof(void*) == sizeof(jint) ? 1 : -1]};
If it's compiled on a system where it's not, you'll get a compilation error.
For slightly less smell, use a static/global map from int to your objects, use an ID generator, and instead of object pointer store relatively unique (within process lifetime) objects IDs within the Java object.

Categories

Resources