In a GPS app that allows the user to display a list of complex location points that we call tracks on various different types of map, each track can consist of between 2k to 10k of location points. The tracks are copiously clipped, pruned and path-simplified when they are rendered on non-Google map types. This is to keep memory usage down and performance up. We typically only wind up submitting far less than a thousand (aggregate) transformed location points to the OpenGL pipeline, even in the worst cases.
In integrating the Google Maps SDK for iOS, we initially attempted to continue to leverage our own OpenGL track rendering system, but ran into issues with conflicting OpenGL context usage (rendering worked, but we couldn't get GMSMapView to and our own internal OpenGL resources to both release without someone touching deleted memory).
So we are trying to leverage the GMSPolyline constructs and just let the Google SDK do the track rendering, but we've run into major memory usage issues, and are looking for guidance in working around them.
Using Xcode Instruments, we've monitored memory usage when creating about 25 poly lines with about 23k location points total (not each). Over the course of poly line creation, app memory usage grows from about 14 MB to about 172 MB, a net peak of about 158 MB. Shortly after all the poly lines are created, memory usage finally drops back down to around 19 MB and seems stable, for a cumulative net of around 5 MB, so it seems each location point requires around 220 bytes (5 MB / 23k points) to store.
What hurts us is the peak memory usage. While our laboratory test only used 23k location points, in the real world there are often many more, and iOS seems to jettison our application after Google Maps has consumed around 450 MB on an iPhone 5 (whereas our internal poly line rendering system peaks at around 12 MB for the same test case).
Clearly the GMSPolyLine
construct is not intended for the heavy weight usage that we require.
We tried wrapping some of the poly line creation loops with separate autorelease pools, and then draining those at appropriate points, but this has no impact on memory use. The peak memory use after the poly lines are created and control is returned to the main run loop didn't change at all. Later it became clear why; the Google Map system isn't releasing resources until the first DisplayLink callback after the poly lines are created.
Our next effort will be to manually throttle the amount of data we're pushing at GMSPolyline, probably using our own bounds testing, clipping, pruning & minimization, rather than relying on Google Maps to do this efficiently.
The drawback here is that it will mean many more GMSPolyline objects will be allocated and deallocated, potentially while the user is panning/zooming around the map. Each of these objects will have far fewer location points, yet still, we're concerned about unforeseen consequences of this approach, hidden overhead of many GMSPolyline allocs and deallocate.
So the question is, what is the best approach for dealing with this situation, and can someone from Google shed some light on any GMSPolyline
best practices, upper bounds, bottlenecks, etc. ?
why don´t you try to use google API for direction, based on basic http requests. https://developers.google.com/maps/documentation/directions/ . (check the conditions on licensing and nº of requests).
And then plot the the data with IOS MKPolyline. i´m Sure you will have better performance. And you will only depend on google for the positioning data.
to convert the response from google API to coordinates, use the well known method (taken from other post) below:
- (NSMutableArray *)parseResponse:(NSDictionary *)response { NSArray *routes = [response objectForKey:@"routes"]; NSDictionary *route = [routes lastObject]; if (route) { NSString *overviewPolyline = [[route objectForKey: @"overview_polyline"] objectForKey:@"points"]; return [self decodePolyLine:overviewPolyline]; } return nil; } -(NSMutableArray *)decodePolyLine:(NSString *)encodedStr { NSMutableString *encoded = [[NSMutableString alloc]initWithCapacity:[encodedStr length]]; [encoded appendString:encodedStr]; [encoded replaceOccurrencesOfString:@"\\\\" withString:@"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])]; NSInteger len = [encoded length]; NSInteger index = 0; NSMutableArray *array = [[NSMutableArray alloc] init]; NSInteger lat=0; NSInteger lng=0; while (index < len) { NSInteger b; NSInteger shift = 0; NSInteger result = 0; do { b = [encoded characterAtIndex:index++] - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1)); lat += dlat; shift = 0; result = 0; do { b = [encoded characterAtIndex:index++] - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1)); lng += dlng; NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5]; NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5]; CLLocation *location = [[CLLocation alloc] initWithLatitude: [latitude floatValue] longitude:[longitude floatValue]]; [array addObject:location]; } return array; }
I had a similar problem with performance on google sdk and it work for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With