SQLite异常:未知错误(代码0):本机无法创建新的byte[]。

3

在查询不超过30个对象时,我遇到了以下错误:每个对象都有一个byte[]字段,它的权重为100x100 ARGB_8888位图数据,大小约为39kb

我使用的是OrmLite 4.45版本,在三星GT n8000平板电脑上(最大堆大小为64mb)

以下是堆栈跟踪:

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)    

以下是日志记录(`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
  • 内存使用量增长如此之快是正常的吗?
  • 您认为将查询拆分成块,并在这些单独的查询之间显式调用System.gc(),这样做有什么影响?

谢谢!


1
将来请展示你的实体问题。仅仅展示日志输出并不能提供关于问题的任何背景信息。 - Gray
1个回答

2

这种内存使用快速增长的情况正常吗?

不,不正常。

你觉得将查询拆分成块,并在这些独立的查询之间显式调用System.gc()有什么作用吗?

不会,这很可能无法解决问题。你需要直接解决潜在的内存问题。

在查看了你发布的代码和实体后,我认为这不是一个ORMLite的问题,而是实体的问题。

你有一个Gallery包含多个Photo。每个照片都有一个可能非常大(可能达到50k)的字节数组图片数据。问题在于Gallery具有Photo的急切外键集合,并且预取了所有的Photo

@ForeignCollectionField(eager = true)
private ForeignCollection<Photo> photos;

每个照片都有其父级相册的自动刷新版本。

@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = GALLERY)
private Gallery gallery;

这将建立一个渴望的获取循环,导致ORMLite执行以下操作:
- 每当ORMLite尝试将 Gallery 加载到内存中时... - 由于渴望的集合,它被要求执行另一个查询并将与 Gallery 关联的所有照片加载到内存中。 - 对于每个 Photo 实例,由于自动刷新的父项,它被要求执行另一个查询以将关联的 Gallery 加载到内存中。 - 对于该 Gallery ,它被要求将所有 Photo 加载到内存中。 - ... ORMLite实际上有一个逃脱机制,但仍会执行此操作3层深。
ORMLite没有对 Gallery Photo 实例的神奇视图,因此它将父 Gallery 附加到 Photo 中的外键字段。 如果您需要这个功能,则可以查看下面的 ObjectCache 解决方案。
您可以通过以下几种方式解决此问题:
  • I'd recommend not using foreignAutoRefresh = true. If you need the Gallery of a photo then you can get it by doing galleryDao.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();
    

灰色,我一直想在我下一个大型应用程序中尝试使用ORMlite。然而,我对当前问题有一个问题——为什么您需要手动清理对象缓存——肯定基于时间的驱逐会是一个好的折衷方案吧?例如,在Guava中,您可以使用.expiresAfterRead(1, TimeUnit.MINUTE)在最后读取超过一分钟后从缓存中删除项目。当然,在您的情况下,您可以做更聪明的特定于用例的度量,但重点仍然存在——这肯定应该自动化吧? - Delyan
你能否将这个问题发到ormlite-users列表中,这样其他人可以从中学习并了解我的回答吗? - Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接