Мы (http://www.mosync.com) скомпилировали наш рекомпилятор ARM с Android NDK, который берет наш внутренний байтовый код и генерирует машинный код ARM. При выполнении перекомпилированного кода мы видим огромное увеличение производительности, с одним небольшим исключением, мы не можем использовать какие-либо операции с битовой картой Java. Собственная система использует функцию, которая берет на себя все вызовы на стороне Java, которые вызывает перекомпилированный код. На стороне Java (Dalvik) у нас есть привязки к функциям Android. При перекомпиляции кода или при выполнении машинного кода проблем нет. Точный же исходный код работает на Symbian и Windows Mobile 6.x, поэтому рекомпилятор, похоже, создает правильный машинный код ARM. Как я уже сказал, проблема заключается в том, что мы не можем использовать объекты Java Bitmap. Мы проверили, что параметры, которые отправляются из Java-кода, являются правильными, и мы попытались выполнить выполнение в собственных JNI-системах Android. Проблема в том, что мы получаем UnsupportedOperationException с "размер должен соответствовать 32 бит". Проблема кажется последовательной на Android 1.5 до 2.3. Мы не пробовали рекомпилятор на любых устройствах Android 3.
Является ли это ошибкой, с которой столкнулись другие люди, я думаю, что другие разработчики сделали аналогичные вещи.
Мне удалось найти работу. Когда я завершаю все вызовы Bitmap.createBitmap внутри Activity.runOnUiThread(), он работает.
Я нашел сообщение в dalvik_system_VMRuntime.c:
/*
* public native boolean trackExternalAllocation(long size)
*
* Asks the VM if <size> bytes can be allocated in an external heap.
* This information may be used to limit the amount of memory available
* to Dalvik threads. Returns false if the VM would rather that the caller
* did not allocate that much memory. If the call returns false, the VM
* will not update its internal counts.
*/
static void Dalvik_dalvik_system_VMRuntime_trackExternalAllocation(
const u4* args, JValue* pResult)
{
s8 longSize = GET_ARG_LONG(args, 1);
/* Fit in 32 bits. */
if (longSize < 0) {
dvmThrowException("Ljava/lang/IllegalArgumentException;",
"size must be positive");
RETURN_VOID();
} else if (longSize > INT_MAX) {
dvmThrowException("Ljava/lang/UnsupportedOperationException;",
"size must fit in 32 bits");
RETURN_VOID();
}
RETURN_BOOLEAN(dvmTrackExternalAllocation((size_t)longSize));
}
Этот метод вызывается, например, из GraphicsJNI :: setJavaPixelRef:
size_t size = size64.get32();
jlong jsize = size; // the VM wants longs for the size
if (reportSizeToVM) {
// SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
bool r = env->CallBooleanMethod(gVMRuntime_singleton,
gVMRuntime_trackExternalAllocationMethodID,
jsize);
Я бы сказал, что код, который вы вызываете, пытается выделить слишком большой размер. Если вы показываете фактический Java-вызов, который терпит неудачу, и значения всех аргументов, которые вы передаете ему, может быть проще найти причину.
Bitmap.createBitmap( 10, 10, Bitmap.Config.ARGB_8888);
Я получу эту проблему. Если я вызываю createBitmap непосредственно в Java, это не проблема, но когда я вызываю то же самое из сгенерированного машинного кода ARM, эта проблема всегда возникает. Все остальные операции в порядке, мы можем инициировать сетевой вызов, Bluetooth, воспроизводить звуки и использоватьnew
для выделения памяти внутри Java. Из всех вещей, которые мы пробовали, это только объект Bitmap, который ломается. Простейший пример, который я пробовал, использовал менее 2 МБ памяти, поэтому при создании небольших растровых изображений не должно быть проблем с памятью.