I have an update routine that runs at the launch of an app. I keep getting
intermittent null reference exceptions (about 1 in 8 runs) at certain points
in my code where this seems not to be possible (My gref count and memory
usage are fine and I believe that I have ruled out any threading issues). 
They always occur at the point of calling ToList() on an IEnumerable<T> or
IList<T>, or at the point of calling foreach on a List<T>.  At these points
I have already determined that the List/IEnumerable is not null and that is
contains a number of items.  In the case of the foreach loop it fails on the
foreach call and never actually gets into the loop.

The routine loops through about 10 different entities and for each one
creates a List<T> which it then uses to insert or update a db.  For most of
these entities there are about 3 points in the code where it has been known
to fail (all ToList or foreach) but will only ever fails at the first point
it hits a tolist or foreach for that entity type.  ie the only way I get it
to fail at the second point is to remove the first tolist of foreach, and
the only way to get it to fail at the third point is to remove the first and
second tolist or foreach.  Or to put it another way if it succeeds at the
first tolist or foreach call for that type it will succeed at all other
points.  

As it is itermittent it is hard to be concrete about anything however it
does not seem to occur in the emulator, only on device.

My understanding of this next bit is limited so appologies if I'm way off
but it seems like it could be relevant:

The common point between both tolist and foreach is that they would both be
calling getenumerator<T>.  From my understanding jit compilation will
compile code for generic types as and when it needs it, after which it
reuses it.  Is it possible that I am hitting some kind of jit issue as the
pattern seems to fit?  Any other suggestions welcome.

Mono 2.10.9 
Mono for Android: 4.4.55

The bits of code that fail are:

1. Calls to this bit which  is from sqlite-net (as used in xamarin mobile
world sample) although I've split this call up for logging.  It fail on
'return ret.ToList()'.  I also have logging in the executedefferedquery and
can see the the IEumerable is populated fine.



        public List<T> ExecuteQuery<T> ()
                                {
                                        var ret = 
ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T)));
                                        
AroundMe.AndroidHelpers.LogDebug("sqlite-c", string.Format("exe q :
{0}", (ret == null).ToString()));
                                        return ret.ToList();
                                        //return 
ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T))).ToList();

                                }


2. This is an update/insert type routine which fails on 'foreach(T entity in
entities)' . I've left in all the logging that I've put in for trying to pin
this down (theres a lot).


protected void InsertUpdateEntities<T>(List<T> entities, string
processStageName, string processStageDisplay, bool deleteExpiredEntities)
where T : class, IEntity, new()
                {
                        try{

                                if(entities == null)
                                        throw new 
ArgumentNullException("entities list");

                                Log.Debug(_logTag, string.Format("started 
insert, count: {0}",
entities.Count.ToString()));

                                UpdateProgressChangedEvenArgs e = new
UpdateProgressChangedEvenArgs(processStageName, processStageDisplay, 0,
false);
                                
                             AndroidHelpers.LogDebug(_logTag," insert getting 
ids");

                                IList<string> existingIds = 
Repository.GetIds<T>();

                                AndroidHelpers.LogDebug(_logTag," insert got 
ids");
        
                                int itemsToUpdate = entities.Count;
                                int itemsUpdated = 0;

                                AndroidHelpers.LogDebug(_logTag, "Transaction 
Starting");
                                Repository.BeginDbTransaction();
                                AndroidHelpers.LogDebug(_logTag, "Transaction 
Started");
                                Log.Debug(_logTag, string.Format("about to 
start for each, count: {0}",
entities.Count.ToString()));
                        //      T[] entitiesArray = new T[entities.Count];
                                //entities.CopyTo(entitiesArray,0);
                        //      AndroidHelpers.LogDebug(_logTag, "array 
copied");
                                foreach(T entity in entities)
                                {
                                        try{
                                                
AndroidHelpers.LogDebug(_logTag, "Checking Contains");
                                                
if(existingIds.Contains(entity.Id))
                                                {
                                                        
AndroidHelpers.LogDebug(_logTag, "Checking Contains : contains");
                                                        
Repository.UpdateItem<T>(entity);
                                                }
                                                else
                                                {
                                                        
AndroidHelpers.LogDebug(_logTag, "Checking Contains : doesn't
contain");
                                                        
Repository.InsertItem<T>(entity);
                                                }
                                        }
                                        catch{
                                                Log.Error(_logTag, 
string.Format("Failed to insert {0}, 1d: {1},
thread {2} , {3}", typeof(T).ToString(), entity.Id, 
Thread.CurrentThread.ManagedThreadId , Java.Lang.Thread.CurrentThread().Id
));
                                        }
                                        
                                        itemsUpdated ++;
                                        
                                        if(itemsUpdated % 10 == 0 || 
itemsUpdated == itemsToUpdate)
                                        {
                                                e.ProgressPercentage = 
(itemsUpdated * 100)/itemsToUpdate;
                                        //      UpdateProgress(e);
                                        }       
                                }
                                


                                // additional code removed.......



                }




--
View this message in context: 
http://mono-for-android.1047100.n5.nabble.com/Possible-JIT-issue-relating-to-generic-list-tp5712901.html
Sent from the Mono for Android mailing list archive at Nabble.com.
_______________________________________________
Monodroid mailing list
Monodroid@lists.ximian.com

UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid

Reply via email to