проверять байт код android что это

Содержание

Введение в байт-код Java

0*rMLC4Ew14zneFpfQ

May 15 · 6 min read

1*zGB84bWzuyTJ mLArMBtKA

Каждому Java-разработчику известно, какую роль в экосистеме языка играет JVM. Однако большинство не разбирается в том, как работает JVM под капотом. Хотя для разработки на Java это не обязательно, код станет лучше, если вы глубже поймете JVM, потому что так вы будете знать, как каждая строка кода влияет на процессы внутри JVM.

Однако для начала нужно понять, что такое байт-код. Итак, поговорим о вводе и выводе байт-кода Java и о том, как он влияет на JVM во время запуска программы.

Что такое байт-код Java?

Если в какой-то момент профессиональной жизни вы слышали, как проповедуют независимость Java-программ от платформ, скажите спасибо байт-коду.

Как генерируется байт-код?

Как посмотреть байт-код Java?

Если вам хочется увидеть сам байт-код, простейший способ — воспользоваться командной строкой.

Как работает JVM

Прежде чем углубляться в байт-код, стоит понять, как JVM его обрабатывает.

Методы — одна из важнейших составляющих кода для JVM. Среда выполнения Java-программы — это, по сути, набор методов, вызываемых JVM. JVM создает фрейм для каждого такого метода и помещает созданный фрейм наверх стека текущего потока для выполнения.

Фрейм состоит из локальной среды, которая необходима для поддержания его выполнения. Как правило он содержит массив локальных переменных и стек операндов. Посмотрим, что эти элементы из себя представляют.

Массив локальных переменных

Массив локальных переменных, как следует из названия, нужен для хранения локальных переменных в методе. Также он хранит аргументы, которые принимает метод.

Определим два метода: один статический и один метод экземпляра, но схожие во всем остальном.

Локальные массивы переменных для этих методов будут выглядеть следующим образом:

Стек операндов

Стек операндов — это рабочее пространство внутри фрейма метода. Поскольку это стек, вы можете помещать и забирать значения только из верхней его части. Большинство инструкций байт-кода, принадлежащих определенному методу, либо участвуют в помещении значений в стек, либо забирают значения из стека для обработки.

Инструкция байт-кода load и ее расширения нужны для перемещения значения, хранящегося в массиве переменных, в стек. Инструкция store применяется для извлечения значений из стека и сохранения в массиве переменных. Существуют и другие инструкции, которые извлекают значения из стека для обработки.

1*MJ6mqP490nKErFoZoNcWEA

Посмотрим в байт-код

Ради возможности вглядеться в байт-код, я написал простой Java-класс:

Деконструкция байт-кода

Здесь важно отметить еще одно: индексы, заданные инструкциям байт-кода — как видим, они не увеличиваются на единицу для каждой новой инструкции.

Число перед инструкцией указывает на индекс ее начального байта. А любой байт-код состоит из однобайтовых опкодов, за которыми следует ноль или более операндов.

Вывод

Надеюсь, вам удалось узнать кое-что новое о том, как работает байт-код Java. С этим более четким знанием вы сможете лучше писать код. Можете даже поэкспериментировать с самим байт-кодом во время выполнения программы, воспользовавшись такими библиотеками, как ASM.

Источник

«Исходный код не соответствует байт-коду» при отладке на устройстве

У меня есть приложение, которое я собираю против уровня API 21: 4bae61ba34c061dfeb73befa89de085f

а затем отлаживать его на реальном устройстве с уровнем API 23:

8d4fe9a3e98e431556f4e487fb34db62

Проблема в том, что, когда я пытаюсь отлаживать собственные классы ОС Android, я получаю «Исходный код не соответствует байт-коду». Почему это происходит? Тестируемое устройство, на котором запущено приложение, является уровнем API 23, а исходный файл, отлаживаемый, также является уровнем 23. 31268a773e33ac7e9a794afba2cd5a07

Я действительно смущен. Может ли кто-нибудь объяснить, почему я вижу это сообщение и как его исправить?

ОТВЕТЫ

Ответ 1

Потенциальные решения, даваемые там (начиная с даты этого сообщения):

Ответ 2

если у вас есть более одной версии библиотеки, это может помочь.

вы получите эти советы

50e33984f4919a940d4935f7c272a584

щелкните значок стрелки

654ef6f5c92eeff67a67a96244a71038

двойной щелчок для выбора правильной библиотеки (обычно самая высокая версия библиотеки правильная)

если вы по ошибке нажали кнопку «отключить», вы можете включить ее в настройках отладчика

ea87785f2091e5b3a0eebb745dbb01cb

если у вас нет подсказок на шаге 3, возможно, вы сможете проверить, проверяли ли вы параметры настройки.

Ответ 3

Вы должны использовать эмулятор Android с тем же уровнем API, что и compileSdkVersion. В вашем случае вам следует использовать эмулятор Android с уровнем API 21.

Ответ 4

Если вы используете Gradle, это, вероятно, проблема с кэшами Gradle. (Ссылка). Увы, даже если вы запустите

он не освежает действительно все зависимости. Остается немного мусора. (Ссылка).

Ответ 5

Я попробовал решения, приведенные здесь, работая над приложением, которое использовало Bluetooth Low Energy (BLE). Я старался,

все это не удалось.

То, что я сделал, было отладка точек, где я думал, что получаю предупреждение, я все еще получал предупреждение, но приложение работало нормально. Вы можете игнорировать предупреждение.

Ответ 6

Перейдите в раздел «Настройки проекта» > «Артефакты». Выберите артефакт, у которого есть проблема. Существует опция «Включить в сборку проекта». Это необходимо проверить (включено). Для более старых версий IntelliJ эта опция «Make on build».

Ответ 7

Вероятно, это сообщение об ошибке может иметь несколько причин, мой случай не был похож на тот, который был у OP, в моем случае это было связано с сторонней библиотекой, которая требовала дополнительных библиотек.

Читайте также:  обезвоживание мкб 10 код

Например: вы вручную добавляете X.jar в свой LIB, но для этого X.jar требуется Z.jar.

Мне понадобилось время, чтобы понять, что сообщение вообще не помогло. Мне пришлось отлаживать приложение до тех пор, пока я не выйду из класса сбоев, и в этом классе убедитесь, что все импортные данные были удовлетворены.

(Particualry: Я добавил MercadoLibre-0.3.4.jar, для которого требуется commons-httpclient.jar)

Надеюсь, это поможет!

Ответ 8

Это также может произойти, если вы включили ProGuard. В buildTypes установите minifyEnabled false, shrinkResources false, useProguard false

Ответ 9

Это решено? Для Android Studio теперь я получаю: «Исходный код Android Studio не совпадает с байтовым кодом»

Ответ 10

Я испробовал все решения, приведенные здесь, и ни одно из них не помогло мне. В версии 2019.1.3 я просто очищаю и перестраиваю артефакт, и он работает; сначала выполните Build → Build Artifacts. → → Clean затем нажмите Build или Rebuild из того же места.

Ответ 11

Мое приложение скомпилировано на API LEVEL 29, но отладка на реальном устройстве на API LEVEL 28. Я получил предупреждение source code does not match the bytecode в AndroidStudio. Я исправил это, думая, что эти шаги:

Перейдите в «Настройки»> «Мгновенный запуск»: снимите флажок «Мгновенный запуск»

Перейти в «Сборка»> «Чистая сборка»

Повторно запустите приложение

Теперь отладка работает нормально.

Ответ 12

Android Studio использует исходную версию, равную целевой версии в вашем приложении. Компиляция выполняется с исходной версией, равной вышеупомянутой версии компиляции. Поэтому позаботьтесь о том, чтобы в вашем проекте Compile Version == Target Version (измените файл build.gradle модуля).

Ответ 13

У меня была такая же проблема, и я нашел решение. Если у вас есть линия, помеченная красным, это выдаст вам эту ошибку, но если вы снимите пометку со всех строк, она будет работать нормально.

под флагом я имею в виду, когда вы нажимаете на левой стороне, где номера строк, и это выделяет линию. Если это не ясно, вот картинки.
перейти от: отмеченной строки к: не отмеченной линии

Источник

Интерпретаторы байт-кодов своими руками

image loader

Виртуальные машины языков программирования в последние десятилетия получили весьма широкое распространение. С презентации Java Virtual Machine во второй половине 90-х прошло уже достаточно много времени, и можно с уверенностью сказать, что интерпретаторы байт-кодов — не будущее, а настоящее.

Но данная техника, на мой взгляд, практически универсальна, и понимание основных принципов разработки интерпретаторов пригодится не только создателю очередного претендента на звание «Язык года» по версии TIOBE, но вообще любому программисту.

Словом, если вам интересно узнать, как складывают числа наши любимые языки программирования, о чём до сих пор спорят разработчики виртуальных машин и как безболезненно сопоставлять строки и регулярные выражения, прошу под кат.

Предыстория

Одна из самописных систем отдела Business Intelligence нашей компании имеет интерфейс в виде несложного языка запросов. В первой версии системы язык этот интерпретировался на лету, без компиляции, непосредственно из входной строки с запросом. Вторая версия парсера будет работать уже с промежуточным байт-кодом, что позволит отделить язык запросов от их выполнения и сильно упростит код.

В процессе работы над второй версией системы у меня случился отпуск, в течение которого я на часик-другой каждый день отвлекался от дел семейных на изучение материалов, посвящённых архитектуре и производительности интерпретаторов байт-кода. Полученными в результате заметками и примерами интерпретаторов я решил поделиться с читателями Хабра в виде серии статей.

В первой из них представлено пять небольших (до сотни строк простенького кода на C) виртуальных машин(ок), каждая из которых раскрывает определённый аспект разработки таких интерпретаторов.

Откуда есть пошли байт-коды в языках программирования

Виртуальных машин, самых разнообразных виртуальных наборов инструкций за последние несколько десятков лет было придумано великое множество. Википедия утверждает, что первые языки программирования стали компилироваться в различные упрощённые промежуточные представления еще в 60-е годы прошлого века. Какие-то из этих первых байт-кодов преобразовывались в машинные коды и выполнялись реальными процессорами, другие — интерпретировались на лету процессорами виртуальными.

Популярность виртуальных наборов инструкций в качестве промежуточного представления кода объясняется тремя причинами:

Давайте сделаем несколько простейших виртуальных машин на C и на этих примерах выделим основные технические аспекты реализации виртуальных машин.

Полные коды примеров выложены на GitHub. Примеры можно собрать любым относительно свежим GCC:

Все примеры имеют одинаковую структуру: сначала идёт код самой виртуальной машины, после — главная функция с assert-ами, проверяющими работу кода. Я старался внятно комментировать опкоды и ключевые места интерпретаторов. Надеюсь, статья будет понятна даже людям, ежедневно не пишущим на C.

Самый простой в мире интерпретатор байт-кода

Как я уже говорил, простейший интерпретатор сделать очень легко. Комментарии — сразу за листингом, а начнём непосредственно с кода:

Здесь меньше ста строк, но все характерные атрибуты виртуальной машины представлены. У машины единственный регистр ( vm.accumulator ), три операции (инкремент регистра, декремент регистра и завершение исполнения программы) и указатель на текущую инструкцию ( vm.ip ).

Операции передаются в функцию vm_interpret в виде массива байтов — байт-кода (англ. bytecode) — и последовательно выполняются до тех пор, пока в байт-коде не встретится операция завершения работы виртуальной машины ( OP_DONE ).

Ключевой аспект виртуальной машины — семантика, то есть набор операций, которые над ней возможны. В данном случае операций только две, и они меняют значение единственного регистра.

Некоторые исследователи (Virtual-machine Abstraction and Optimization Techniques, 2009) предлагают разделять виртуальные машины на высокоуровневые и низкоуровневые по близости семантики виртуальной машины к семантике физической машины, на которой будет выполняться байт-код.

В предельном случае байт-код низкоуровневых виртуальных машин может полностью повторять машинный код физической машины с имитацией оперативной памяти, полным набором регистров, инструкциями работы со стеком и так далее. Виртуальная машина Bochs, например, повторяет набор инструкций архитектуры x86.

Читайте также:  коды для роблокс мускул ледженс

И наоборот: операции высокоуровневых виртуальных машин близко отражают семантику компилируемого в байт-код специализированного языка программирования. Так работают, например, SQLite, Gawk и многочисленные версии Prolog.

Промежуточное положение занимают интерпретаторы языков программирования общего назначения, имеющие элементы как высокого, так и низкого уровней. В популярнейшей Java Virtual Machine есть как низкоуровневые инструкции для работы со стеком, так и встроенная поддержка объектно-ориентированного программирования с автоматическим выделением памяти.

Приведённый же код относится скорее к самым примитивным из низкоуровневых виртуальных машин: каждая виртуальная инструкция — обёртка над одной-двумя физическими инструкциями, виртуальный регистр же полностью соответствует одному регистру «железного» процессора.

Аргументы инструкций в байт-коде

Можно сказать, что единственный регистр в нашем примере виртуальной машины — одновременно и аргумент, и возвращаемое значение всех выполняемых инструкций. Однако нам может пригодиться возможность передавать аргументы в инструкции. Один из способов — прямо помещать их в байт-код.

Расширим пример, внеся инструкции (OP_ADDI, OP_SUBI), принимающие аргумент в виде байта, следующего непосредственно за опкодом:

Новые инструкции (см. функцию vm_interpret ) читают из байт-кода свой аргумент и прибавляют его к регистру / вычитают его из регистра.

Такой аргумент называется непосредственным аргументом (англ. immediate argument), поскольку он располагается прямо в массиве опкодов. Главное ограничение в нашей реализации заключается в том, что аргумент представляет собой один-единственный байт и может принимать только 256 значений.

В нашей виртуальной машине диапазон возможных значений аргументов инструкций не играет большой роли. Но если виртуальная машина будет использоваться в качестве интерпретатора настоящего языка, то имеет смысл усложнить байт-код, добавив в него отдельную от массива опкодов таблицу констант и инструкции с непосредственным аргументом, соответствующим адресу настоящего аргумента в таблице констант.

Стековая машина

Инструкции в нашей несложной виртуальной машине всегда работают с одним регистром и никак не могут передавать друг другу данные. Кроме того, аргумент у инструкции может быть только непосредственный, а, скажем, операции сложения или умножения принимают два аргумента.

Проще говоря, у нас нет никакой возможности вычислять сложные выражения. Для решения этой задачи необходима стековая машина, то есть виртуальная машина со встроенным стеком:

В этом примере операций уже больше, и почти все они работают только со стеком. OP_PUSHI помещает на стек свой непосредственный аргумент. Инструкции OP_ADD, OP_SUB, OP_DIV, OP_MUL извлекают по паре значений из стека, вычисляют результат и помещают его обратно на стек. OP_POP_RES снимает значение со стека и помещает его в регистр result, предназначенный для результатов работы виртуальной машины.

Для операции деления (OP_DIV) отлавливается ошибка деления на ноль, что останавливает работу виртуальной машины.

Возможности такой машины намного шире предыдущей с единственным регистром и позволяют, например, вычислять сложные арифметические выражения. Другим (и немаловажным!) преимуществом является простота компиляции языков программирования в байт-код стековой машины.

Регистровая машина

Благодаря своей простоте стековые виртуальные машины получили самое широкое распространение среди разработчиков языков программирования; те же JVM и Python VM используют именно их.

Однако у таких машин есть и недостатки: в них приходится добавлять специальные инструкции для работы со стеком, при вычислении выражений все аргументы многократно проходят через единственную структуру данных, в стековом коде неизбежно появляется множество лишних инструкций.

Между тем выполнение каждой лишней инструкции влечёт за собой затраты на диспетчеризацию, то есть декодирование опкода и переход к телу инструкций.

Альтернатива стековым машинам — регистровые виртуальные машины. У них более сложный байт-код: в каждой инструкции явно закодированы номер регистров-аргументов и номер регистра-результата. Соответственно, вместо стека в качестве хранилища промежуточных значений используется расширенный набор регистров.

В примере показана регистровая машина на 16 регистров. Инструкции занимают по 16 бит каждая и кодируются тремя способами:

У нашей небольшой виртуальной машины совсем мало операций, поэтому четырёх бит (или 16 возможных операций) на опкод вполне достаточно. Операция определяет, что именно представляют оставшиеся биты инструкции.

Первый вид кодирования (4 + 4 + 8) нужен для загрузки данных в регистры операцией OP_LOADI. Второй вид (4 + 4 + 4 + 4) используется для арифметических операций, которые должны знать, где брать пару аргументов и куда складывать результат вычисления. И, наконец, последний вид (4 + 4 + 8 ненужных бит) используется для инструкций с единственным регистром в качестве аргумента, в нашем случае это OP_MOV_RES.

Для кодирования и декодирования инструкций теперь нужна специальная логика (функция decode ). С другой стороны, логика инструкций благодаря явному указанию на расположение аргументов становится проще — исчезают операции со стеком.

Ключевые особенности: в байт-коде регистровых машин меньше инструкций, отдельные инструкции шире, компиляция в такой байт-код сложнее — компилятору приходится решать, как использовать доступные регистры.

Надо заметить, что на практике в регистровых виртуальных машинах обычно есть и стек, куда помещаются, например, аргументы функций; регистры же используются для вычисления отдельных выражений. Даже если явного стека нет, то для построения стека используется массив, играющий ту же роль, что оперативная память в физических машинах.

Стековые и регистровые машины, сравнение

Есть интересное исследование (Virtual machine showdown: Stack versus registers, 2008), оказавшее большое влияние на все последующие разработки в области виртуальных машин для языков программирования. Его авторы предложили способ прямой трансляции из стекового кода стандартной JVM в регистровый код и сравнили производительность.

Способ нетривиальный: код сначала транслируется, а потом достаточно сложным образом оптимизируется. Но последующее сравнение производительности одной и той же программы показало, что дополнительные циклы процессора, затраченные на декодирование инструкций, полностью компенсируются уменьшением общего числа инструкций. В общем, если коротко, регистровая машина оказалась эффективнее стековой.

Как уже упоминалось выше, у этой эффективности есть вполне осязаемая цена: компилятор должен сам аллоцировать регистры и дополнительно желательно наличие развитого оптимизатора.

Читайте также:  питер код города телефонный

Спор о том, какая же архитектура лучше, всё ещё не закончен. Если говорить о компиляторах Java, то байт-код Dalvik VM, до недавних пор работавший в каждом Android-устройстве, был регистровым; но титульная JVM сохранила стековый набор инструкций. Виртуальная машина Lua использует регистровую машину, но Python VM — по-прежнему стековая. И так далее.

Байт-код в интерпретаторах регулярных выражений

Наконец, чтобы отвлечься от низкоуровневых виртуальных машин, давайте рассмотрим специализированный интерпретатор, проверяющий строки на соответствие регулярному выражению:

Главная инструкция — OP_CHAR. Она берёт свой непосредственный аргумент и сравнивает его с текущим символом в строке ( char *sp ). В случае совпадения ожидаемого и текущего символов в строке происходит переход к следующей инструкции и следующему символу.

Машина также понимает операцию перехода (OP_JUMP), принимающую единственный непосредственный аргумент. Аргумент означает абсолютное смещение в байт-коде, откуда следует продолжать вычисление.

Последняя важная операция — OP_OR. Она принимает два смещения, пробуя применить сначала код по первому из них, потом, в случае ошибки, второму. Делает она это при помощи рекурсивного вызова, то есть инструкция делает обход в глубину дерева всех возможных вариантов регулярного выражения.

Удивительно, но четырёх опкодов и семидесяти строк кода достаточно, чтобы выразить регулярные выражения вида «abc», «a?bc», «(ab|bc)d», «a*bc». В этой виртуальной машине даже нет явного состояния, так как всё необходимое — указатели на начало потока инструкций, текущую инструкцию и текущий символ — передаётся аргументами рекурсивной функции.

Если вам интересны детали работы движков регулярных выражений, для начала можете ознакомиться с серией статей Расса Кокса (англ. Russ Cox), автора движка для работы с регулярными выражениями от Google RE2.

Итоги

Давайте подведём итоги.

Для языков программирования общего назначения используются, как правило, две архитектуры: стековая и регистровая.

В стековой модели основной структурой данных и способом передачи аргументов между инструкциями является стек. В регистровой модели для вычисления выражений используется набор регистров, но для хранения аргументов функций всё равно используется явный или неявный стек.

Наличие явного стека и набора регистров приближает такие машины к низкоуровневым и даже физическим. Обилие низкоуровневых инструкций в таком байт-коде означает, что существенные затраты ресурсов физического процессора приходятся на декодирование и диспетчеризацию виртуальных инструкций.

С другой стороны, в популярных виртуальных машинах большую роль играют и высокоуровневые инструкции. В Java, например, это инструкции полиморфных вызовов функций, аллокация объектов и сборка мусора.

Чисто высокоуровневые виртуальные машины — к примеру, интерпретаторы байт-кодов языков с развитой и далёкой от железа семантикой — большую часть времени проводят не в диспетчере или декодере, а в телах инструкций и, соответственно, относительно эффективны.

В следующих статьях я разберу практические реализации виртуальных машин в популярных языках программирования и расскажу, зачем отделу Business Intelligence Badoo понадобился байт-код.

Источник

Как объяснить, что такое байткод? [закрыт]

Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах.

7 ответов 7

Легко будет объяснить и переносимость. Если человек (секретарша) выучит все коды операций, то она сможет выполнить любую работу, главное, что бы была последовательность кодов. А инженеры могут попробовать спаять-сконструировать устройство, которое будет это исполнять.

@vanyamelikov по-моему вы сами не понимаете что такое байткод Java 🙂

Байткод Java это машинные инструкции для несуществующей Java машины, которую часто называют Java Virtual Machine.

В чем сила брат? А сила брат в том, что вы пишете для некоей Java машины (когда-нибудь кто-нибудь сделает таки физическую Java машину). Что такое портабельность Java кода: это всего лишь вопрос реализации Java машины на какой-то реальной машине ну и т.д.

Я бы попытался объяснить как-то так:

Компьютеры «думают» простейшими инструкциями, и когда вы пишете программу допустим на С то она преобразуется в набор примитивных машинных инструкций. Например было выражение на языке программирования

Оно грубо говоря преобразуется в последовательность инструкций

Так как компьютеры бывают разные то и инструкции которые они используют тоже не всегда одни и те же.

Буду рад услашать критику по поводу подобного объяснения^_^

Я так понимаю, вопрос в том, как объяснить, что такое байт-код, не прибегая к объяснению остального контекста. Мне кажется, что не получится объяснить, что такое байт-код, не объяснив, что такое машинный язык и язык программирования, потому что он ведь не сам по себе, он прослойка между ними — т.е. чтобы понять, что делает прослойка, нужно понять, между чем она лежит.

Самый лучший способ практический:

photo

NMBDq

Зачем придумали байт-код? В начале были интерпретаторы которые просто выполняли код из текста, но так как эффективность в постоянном разборе строк не есть хорошо, придумали работать с байтами, а не как с исходным кодом строк, то есть программа преобразует исходный синтаксис ЯП-а в байт-код где есть инструкции и метки и т.п. почти как в ASM, отсюда и происходит название виртуальная машина, а не интерпретатор, к примеру в Java это JVM. Так что тут всё просто, виртуальная машина при загрузке байт-кода исполняет его. Но это ещё не всё, для большей производительности ввели JIT, то есть компиляции байт-кода в нативный код на ходу исполнения, тем самым не много получаем конкурентоспособность программ к компилируемым ЯП-ам.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками c# c java байткод c++ или задайте свой вопрос.

Похожие

дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.11.2.40632

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Источник

Поделиться с друзьями
admin
Здоровый образ жизни: советы и рекомендации