问题
I'm getting this error when trying to query up to 30 objects, each object has field byte[] which weights 100x100 ARGB_8888 bitmap data ~ 39kb
I'm using OrmLite 4.45 version. on a Samsung GT n8000 tablet (max heap size 64mb)
Here's stacktrace:
android.database.sqlite.SQLiteException: unknown error (code 0): Native could not create new byte[]
at android.database.CursorWindow.nativeGetBlob(Native Method)
at android.database.CursorWindow.getBlob(CursorWindow.java:403)
at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:45)
at com.j256.ormlite.android.AndroidDatabaseResults.getBytes(AndroidDatabaseResults.java:161)
at com.j256.ormlite.field.types.ByteArrayType.resultToSqlArg(ByteArrayType.java:41)
at com.j256.ormlite.field.BaseFieldConverter.resultToJava(BaseFieldConverter.java:24)
at com.j256.ormlite.field.FieldType.resultToJava(FieldType.java:798)
at com.j256.ormlite.stmt.mapped.BaseMappedQuery.mapRow(BaseMappedQuery.java:60)
at com.j256.ormlite.stmt.SelectIterator.getCurrent(SelectIterator.java:270)
at com.j256.ormlite.stmt.SelectIterator.nextThrow(SelectIterator.java:161)
at com.j256.ormlite.stmt.StatementExecutor.query(StatementExecutor.java:187)
at com.j256.ormlite.dao.BaseDaoImpl.query(BaseDaoImpl.java:263)
at com.j256.ormlite.dao.EagerForeignCollection.(EagerForeignCollection.java:37)
at com.j256.ormlite.field.FieldType.buildForeignCollection(FieldType.java:781)
at com.j256.ormlite.stmt.mapped.BaseMappedQuery.mapRow(BaseMappedQuery.java:82)
at com.j256.ormlite.android.AndroidDatabaseConnection.queryForOne(AndroidDatabaseConnection.java:186)
at com.j256.ormlite.stmt.mapped.MappedQueryForId.execute(MappedQueryForId.java:38)
at com.j256.ormlite.field.FieldType.assignField(FieldType.java:540)
at com.j256.ormlite.stmt.mapped.BaseMappedQuery.mapRow(BaseMappedQuery.java:71)
at com.j256.ormlite.stmt.SelectIterator.getCurrent(SelectIterator.java:270)
at com.j256.ormlite.stmt.SelectIterator.nextThrow(SelectIterator.java:161)
at com.j256.ormlite.stmt.StatementExecutor.query(StatementExecutor.java:187)
at com.j256.ormlite.dao.BaseDaoImpl.query(BaseDaoImpl.java:263)
at com.j256.ormlite.stmt.QueryBuilder.query(QueryBuilder.java:319)
at com.j256.ormlite.stmt.Where.query(Where.java:485)
at com.j256.ormlite.dao.BaseDaoImpl.queryForEq(BaseDaoImpl.java:243)
here's logcat:
05-16 14:05:24.561: D/dalvikvm(4163): GC_CONCURRENT freed 1247K, 10% free 18046K/19911K, paused 11ms+3ms, total 30ms
05-16 14:05:24.561: D/dalvikvm(4163): WAIT_FOR_CONCURRENT_GC blocked 10ms
05-16 14:05:24.686: D/dalvikvm(4163): GC_CONCURRENT freed 119K, 4% free 19922K/20743K, paused 11ms+2ms, total 28ms
05-16 14:05:24.686: D/dalvikvm(4163): WAIT_FOR_CONCURRENT_GC blocked 15ms
... whole ton of these
05-16 14:05:27.261: D/dalvikvm(4163): GC_CONCURRENT freed 109K, 2% free 62754K/63495K, paused 12ms+5ms, total 36ms
05-16 14:05:27.261: D/dalvikvm(4163): WAIT_FOR_CONCURRENT_GC blocked 20ms
05-16 14:05:27.366: I/dalvikvm-heap(4163): Clamp target GC heap from 65.738MB to 64.000MB
- Is such fast growth of memory usage normal?
- What do you think about splitting query into chunks and explicitly calling System.gc() between those separate queries?
Thanks!
回答1:
Is such fast growth of memory usage normal?
No it isn't.
What do you think about splitting query into chunks and explicitly calling System.gc() between those separate queries?
No, this most likely would not fix the issue. You need to resolve the underlying memory issue directly.
After looking at your code and entities that you did not provide in your post, this is not a ORMLite issue but a entity problem.
You have a Gallery
of Photo
s. Each photo has a possibly large array of byte image data -- maybe 50+k. The problem is that the Gallery
has an eager foreign collection of Photo
s:
@ForeignCollectionField(eager = true)
private ForeignCollection<Photo> photos;
And then each Photo
has an auto-refreshed version of its parent Gallery
.
@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = GALLERY)
private Gallery gallery;
This sets up an eager fetch loop which causes ORMLite to do something like the following:
- Whenever ORMLite tries to load the
Gallery
into memory... - it is being asked to do another query and load all of the photos associated with the
Gallery
into memory because of the eager collection. - For each of those
Photo
instances, it is being asked to do another query to get the associatedGallery
into memory because of the auto-refreshed parent. - And for that
Gallery
it is asked to load all of thePhoto
s into memory. - ... ORMLite actually has an escape but still does this 3 levels down.
ORMLite has no magic view of the Gallery
and Photo
instances so it attach the parent Gallery
to the foreign field in the Photo
s. If you want this then I'd see the ObjectCache
solution below.
There are a number of ways you can fix this:
- I'd recommend not using
foreignAutoRefresh = true
. If you need theGallery
of a photo then you can get it by doinggalleryDao.refresh(photo.getGallery())
. This breaks the chain of eager fetches. - You could also make the
photos
collection not be eager. A lazy loaded collection would go more times to the database but would also break the cycle. If you really must have all of the eager collection and refreshing then the best solution however would be the introduction of an
ObjectCache
. You may have to clear the cache often but each of the DAOs would then look in the cache and return the same object entity even with the eager fetch loop going on.galleryDao = getHelper().getRuntimeExceptionDao(Gallery.class); galleryDao.setObjectCache(true); photoDao = getHelper().getRuntimeExceptionDao(Photo.class); photoDao.setObjectCache(true); ... // if you load a lot of objects into memory, you must clear the cache often galleryDao.clearObjectCache(); photoDao.clearObjectCache();
来源:https://stackoverflow.com/questions/16585221/sqliteexception-unknown-error-code-0-native-could-not-create-new-byte