Android NDK mmap вызывается на 32-битных устройствах после обновления до Lollipop

Я пытаюсь захватить 784 мегабайта памяти. Да, я знаю, что это очень много для 32-битного телефона, но следующий телефон работал до Android 5.0:

mmap(0, 0x31000000, PROT_NONE, MAP_ANON | MAP_SHARED, -1, 0); 

Однако на трех разных устройствах от разных производителей обновление до Android 5.0 нарушило это. Я предполагаю, что это некоторые изменения в функции распределения памяти в 5.0; Возможно, нужно передать разные флаги?

Вот сообщение об ошибке, возвращаемое в logcat:

 E/libc﹕ mmap fail (pid 9994, tid 10125, size 822083584, flags 0x21, errno 12(Out of memory)) 

    В момент, когда mmap() не работает, откройте /proc/self/maps скопируйте содержимое в временный файл, затем просмотрите файл в редакторе. Вы должны увидеть кучу записей вроде этого:

     12e01000-42c00000 ---p 00201000 00:04 11639 /dev/ashmem/dalvik-main space (deleted) 55281000-5d500000 r--s 00000000 00:16 61 /storage/sdcard1/blah 5d500000-67e80000 rw-p 00000000 00:00 0 [anon:libc_malloc] 67ea4000-682cc000 r-xp 00000000 b3:17 114807 /system/vendor/lib/libsc-a3xx.so 682cc000-682f4000 r--p 00427000 b3:17 114807 /system/vendor/lib/libsc-a3xx.so 

    Номера слева представляют собой диапазоны виртуальных адресов (начало / конец) для процесса. Когда вы создаете новое сопоставление, он должен вписываться в промежуток между сопоставлениями.

    В приведенном выше примере есть хороший большой разрыв между окончанием первой записи в 0x42c00000 и началом следующего в 0x55281000. Это около 294 МБ. Между двумя соседями нет места, и только после этого.

    Если вы посмотрите на карту процесса и не найдете достаточно большого пробела для хранения вашего файла, у вас есть свой ответ. Область между 0x00000000 и 0xbfffffff обычно доступна для 32-разрядных приложений, но инфраструктура приложения использует ее много. (Верхняя 1 ГБ отображается на ядро.)

    Я предполагаю, что некоторая комбинация ASLR и изменения способа распространения виртуальной памяти в Lollipop привели к этой проблеме. На карте, прикрепленной к этому аналогичному вопросу , наибольший разрыв был около 300 МБ. Есть два крупных региона «далвик», один 768 МБ (в 12e01000), один 1,2 ГБ (на 84d81000). (Поскольку вы используете Lollipop, это на самом деле связано с ART, а не с Dalvik, но, по-видимому, ярлык застрял.)

    Одна из возможностей заключается в том, что у АРТ более высокие требования к виртуальной памяти, чем у Dalvik, и большие ассигнования затрудняют приложения для получения областей с крупными картами. Также возможно, что АРТ чрезмерно распределяется из-за ошибки. Вы можете протестировать на Marshmallow, чтобы узнать, исправлено ли что-то.

    В любом случае вы не можете создать сопоставление, если область смежных областей виртуальной памяти не будет достаточно большой, чтобы ее удерживать. С использованием рамок приложения и огромными распределениями АРТ, рассмотренными в другом вопросе, сопоставление 768 МБ было бы невозможно, даже если виртуальное адресное пространство не было фрагментировано. Вам нужно будет отобразить меньшие разделы файла и, возможно, отобразить их, когда вы работаете, чтобы освободить место.

    Возможно, стоит указать ошибку на b.android.com . Прикрепите копию файла карты процесса и укажите версию Android и устройства.

    Для получения более подробной информации о интерпретации / proc / maps см., Например, этот ответ .

    • Перекомпилируйте свою библиотеку приложений в соответствии с леденцом и повторите попытку.
    • Обновите свой SDK
    • Обязательно установите целевую платформу на леденец в настройках вашего приложения
    • Уменьшите выделенную память и снова проверьте

    Вы пробовали вариант largeHeap?

    В особых ситуациях вы можете запросить больший размер кучи, установив для атрибута largeHeap значение «true» в теге манифеста. Если вы это сделаете, вы можете вызвать getLargeMemoryClass (), чтобы получить оценку большого размера кучи.

    https://developer.android.com/training/articles/memory.html#CheckHowMuchMemory

    Подробнее:

    https://developer.android.com/guide/topics/manifest/application-element.html#largeHeap