Связующее, предотвращающее сбор мусора - PullRequest
5 голосов
/ 02 ноября 2011

Мне кажется, я обнаружил утечку памяти и хочу подтвердить, что, по моему мнению, может быть правдой в отношении реализации Android Binder.В этом случае у меня есть Сервис и Активность, каждый в своем собственном процессе.Я создал AIDL, который позволяет мне передавать объект Callback из Activity в Сервис через метод ipc, а затем вызывать callback, когда Служба завершается с запрошенной задачей.

В течение долгого времени я былинтересно: если я передаю новый объект обратного вызова в службу и не сохраняю указатель на объект обратного вызова в моей деятельности , почему сборщик мусора просто не собирается собирать обратный вызов в процессе своей деятельности? Так как этого, кажется, не происходит, как JVM знает, когда собирать мусор для обратного вызова в моей активности.

Я думаю, что ответ заключается в том, что система Binder сохраняет указатель на мой обратный вызов в действииобрабатывать до тех пор, пока соответствующему объекту обратного вызова в сервисном процессе не будет вызван метод finalize (), который затем отправит сообщение Activity, чтобы освободить указатель. Это правильно?Если нет, то как это работает?

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

Ответы [ 2 ]

6 голосов
/ 19 мая 2012

Юрий в значительной степени прав.

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

Однако объект обратного вызова в Activity будет продолжать указываться системой привязки Android до тех пор, пока соответствующий объект обратного вызова в Сервисе не будет собран мусором.

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

Если класс обратного вызова является нестатическим внутренним классом, вы можете подумать о том, чтобы заменить его статическим внутренним классом и передать родительский класс в конструктор, таким образом, вы можете также обнулить это в destory() способ.

Это вызывает интересную мысль, если родительский класс нестатического внутреннего класса обратного вызова - это Activity, и изменение конфигурации происходит (например, поворот экрана) после того, как обратный вызов отправляется через связыватель, но до его вызова тогда обратный вызов будет указывать на старый объект Activity при запуске!

Обновление : я обнаружил этот код в Binder.java, конечно, он отключен, но было бы неплохо, если бы они упоминали подобные вещи в Javadocs.

    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Binder> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
1 голос
/ 27 января 2012

Если я правильно понимаю, как работает Binder, проблема в вашем случае заключается в следующем. Для каждого входящего входящего звонка ваш Сервис создает отдельную ветку. Когда вы передаете объект в этот поток, ваша система Binder создает локальную копию вашего объекта для потока. Таким образом, пока ваш метод Service не вернет результат, поток с копией объекта продолжает работать.

Чтобы проверить это, просто попробуйте увидеть потоки вашего процесса службы (в DDMS).

...