SQLiteException:未知错误(代码0):Native无法创建新的byte []

时间:2013-05-16 10:38:10

标签: android out-of-memory ormlite

我在尝试查询最多30个对象时遇到此错误,每个对象都有字段byte [] ,其权重为100x100 ARGB_8888位图数据 ~39kb < / p>

我使用的是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 个答案:

答案 0 :(得分:2)

  

内存使用率如此快速增长是否正常?

不,不是。

  

您如何看待将查询分成块并在这些单独的查询之间显式调用System.gc()?

不,这很可能无法解决问题。您需要直接解决基础内存问题。

查看您在帖子中未提供的代码和实体后,这不是ORMLite问题,而是实体问题。

您有GalleryPhoto。每张照片都有一大堆字节图像数据 - 可能是50 + k。问题是Gallery有一个热切的外国集合Photo s:

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

然后每个Photo都有其父Gallery的自动刷新版本。

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

这会设置一个急切的提取循环,使ORMLite执行以下操作:

  1. 每当ORMLite尝试将Gallery加载到内存中时......
  2. 由于热切的收集,它被要求进行另一次查询并将与Gallery相关联的所有照片加载到内存中。
  3. 对于每个Photo个实例,由于自动刷新的父级,系统会要求它执行另一个查询以将关联的Gallery放入内存。
  4. 对于Gallery,系统会要求将所有Photo加载到内存中。
  5. ...... ORMLite实际上有一个逃脱,但仍然会降低3级。
  6. ORMLite没有GalleryPhoto个实例的神奇视图,因此它将父Gallery附加到Photo s中的外部字段。如果你想要这个,那么我会在下面看到ObjectCache解决方案。

    您可以通过多种方式解决此问题:

    • 我建议使用foreignAutoRefresh = true 。如果您需要照片的Gallery,那么您可以通过galleryDao.refresh(photo.getGallery())获取照片。这打破了一连串的渴望。
    • 你也可以让photos集合渴望。延迟加载的集合会更多次访问数据库,但也会破坏循环。
    • 如果确实必须拥有所有热切的收集和刷新,那么最好的解决方案就是引入ObjectCache。您可能必须经常清除缓存,但每个DAO都会查看缓存并返回相同的对象实体,即使正在进行eager fetch循环。

      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();