Pull to refresh
23
0
Семён Солдатенко @SamSol

User

Send message
Ой, извиняюсь.
При выключенном «Don't keep Activities» всё работает
— во время пересоздания Garbage Collector не уничтожает IdentityParcelable (на него ссылается Bundle)
— после создания и последующего удаления Activity ссылка на IdentityParcelable освобождается и утечка памяти не происходит (Bundle уничтожается)

Если включить «Don't keep Activities» тоже всё работает. Но я не проверил удерживает ли Parcel ссылку на ReferenceBinder во время пересоздания Activity. Или может быть Bundle как и раньше удерживает ссылку на IdentityParcelable…
Я только проверил, что после пересоздания и удаления Activity нет утечки памяти.
Пока анализировал нашел багу ;-(.
1. Ориентация портрет
2. Запуск приложения
3. Тап на кнопку Length
4. Тап на кнопку Calculate Length
5. Ориантация альбом
6. Нажать аппаратную кнопку Home
7. Ориентация портрет
8. Запуск приложения
Ожидаемое состояние: Текст «Lengh of is 0»
Действительное состояние: Текст «Calculating length of. Step 60 of 100.» (и не меняется).
Мне удалось проверить, что:
Ссылка на ActivityRecord удерживается пока существует Bundle в который записали instance state.
Ссылка на ActivityRecord удаляется когда удаляется Bundle в который ее записали.

Но не удалось заставить систему восстановить ReferenceBinder из Parcel!
IdentityParcelable createFromParcel(Parcel source) — не вызывается чтобы я ни делал. Такое ощущение, что Bundle хранит ссылку на Parcelable, и игнорирует все что записали в Parcel.

Для проверки гипотезы я удалил из IdentityParcelable всё вплоть до ReferenceBinder и не нашел никаких изменений в работе приложения.
public class IdentityParcelable implements Parcelable {

    public static final Parcelable.Creator<IdentityParcelable> CREATOR = new Creator<IdentityParcelable>() {
        @Override
        public IdentityParcelable createFromParcel(Parcel source) {
            throw new RuntimeException("Not implemented");
        }

        @Override
        public IdentityParcelable[] newArray(int size) {
            throw new RuntimeException("Not implemented");
        }
    };

    public final Object content;

    public IdentityParcelable(Object content) {
        this.content = content;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }
}

Эта реализация работает так же как ваша (и не использует никаких Binder/IBinder).
Loader-ы (и в частности AsyncTaskLoader) очень хорошо справляются с задачей асинхронной загрузки и повторной асинхронной загрузки данных. Только их нужно использовать совместно с LoaderManager.
Уверены, что в вашем коде нет утечки которая очевидна в моем коде?
Функциональный аналог IdentityParcelable может быть очень простым: статический HashMap<Serializable, Object> и несложный код доступа.
Например так:
class IdentityParcelable implements Serializable {
    private static HashMap<UUID, Object> cache = new HashMap<>();
    private static HashMap<Object, UUID> reverseCache = new HashMap<>();

    private UUID id;

    public IdentityParcelable() {
    }

    public IdentityParcelable(Object o) {
        if (reverseCache.containsKey(o)) {
            id = reverseCache.get(o);
        } else {
            id = UUID.randomUUID();
            cache.put(id, o);
            reverseCache.put(o, id);
        }
    }

    public Object getObject() {
        return cache.get(id);
    }
}

В чём, по-вашему, этот простой аналог уступает предложенному вами коду?
Дождался когда ошибка стала проявляться (4 дня после рестарта).
Прописал UseDNS no, рестартовал sshd `sudo systemctl restart sshd.service`.
Ошибка продолжает проявляться. Вообще без изменений.

Рестартовал сервер — логин за секунду. Жду, когда снова начнет тупить.
Кто-нибудь знает в чем проблема с глючным systemd-logind.service?
Симптомы
  1. медленный логин по ssh (~20 секунд)
  2. в логах journald такие сообщения:
    dbus[633]: [system] Failed to activate service 'org.freedesktop.login1': timed out
    sshd[10643]: pam_systemd(sshd:session): Failed to create session: Failed to activate service 'org.freedesktop.login1': timed out

После рестарта командой

sudo systemctl restart systemd-logind.service

на несколько дней все приходит в норму.
Сервер без нагрузки: 2-3 ssh сессий в минуту (git) «Ubuntu 15.10 (GNU/Linux 4.2.0-16-generic i686)».
Как и другие комментаторы рекомендую изучать теорию. Однако эти занятия потребуют значительных усилий и несколько подорвут уверенность в собственных силах :-(. Так что будьте готовы.

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

p.s. рекомендую programmingcomputervision.com (качайте внизу страницы final draft).
56. Сделайте несколько псевдонимов для метода.
function open() {
...
}
function close() {
...
}

module.exports = {
    open: open,
    close: close,
    show: open, // <---- WTF?!
}

Объясняйте это тем, что иногда забываете конкретное имя метода. run(), start(), do()? или open(), show(), display().
О, это хороший вопрос! Как это сделать технически уже показал AMar4enko.

А вот с точки зрения архитектуры…
Если есть модель данных, то начальные значения этих данных должны определяться в том месте где эта модель создается (или там где заполняется — если данных загружаются асинхронно). Получается, что в случае, когда поле ввода «привязано» к модели данных с помощью ng-model конструкция habr-remember-in-cookie окажется вредной :-(

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

Хороший код. Вот что бы я еще с ним сделал:

— для наглядности я бы прописал имя куки в атрибут saveable (и чтобы отвязаться от имени поля в именах кук)
— исправил ошибку с восстановлением значения только в случае если поле не заполнено
— и пожалуй переименовал бы атрибут во что-нибудь вроде save-to-cookie (или data-my-save-to-cookie)

jsfiddle.net/dzb5rcsw/2

Получился отличный jQuery код. От решения на AngularJS отличается только тем, что здесь код помещается в общую кучу, а в AngularJS он оформляется во вполне определенный компонент (директиву), и немного лучше подходит для повторного использования или модульного тестирования.

Нужен ли AngularJS ради такой мелочи?

А если таких мелочей хотя бы штук 5? Тогда в AngularJS будет 5 простых директив, а в JQuery 10 фрагментов. Которые со временем мигрируют в один блок $(document).ready(funtion() {}); и будет потеряна возможность модульного тестирования каждого фрагмента по отдельности.
Здесь я использую jquery-cookie для наглядности. Так как angular-cookie (когда я в последний раз на него смотрел) не позволяет кратко задать срок действия cookie.

В вашем примере (с использованием angular-cookie) testCookie является сессионным cookie. И при повторных входах пользователей значение не будет восстановлено. Такое решение мне не подходит.

В angular-1.4.0-beta.6 модуль angular-cookie уже доработан, поэтому когда он выпустится в релиз, можно будет отметить это здесь.
Ага, представьте как будет выглядеть эта проверка после while:
while(buf->head != buf->tail) {
...
}
WARN_ON(buf->head != buf->tail);


Хочу сказать, что проверка стала не лишней, а бессмысленной.
Еще одно отличие. В оригинальном коде во время вызова tty_buffer_free в tty->buf.head лежит ссылка на следующий элемент. А в вашем коде там лежит ссылка на удаляемый элемент.
ИМХО — слишком вольные изменения.
Изначально код удалял все элементы списка по порядку с первого по последний (включительно).
Ваш код стал удалять все элементы списка по порядку с первого до последнего (но последний не удаляется).

Почему бы прямо так и не написать в коде?

while(tty->buf.head != tty->buf.tail) {
    thead = tty->buf.head;
    tty->buf.head = thead->next;
    tty_buffer_free(tty, thead);
}

Совсем без тестов?! Karma, Protractor… Ничего такого не было?!
1) Попробуйте покрыть свой код юнит-тестами на 100% (сможете увидеть несколько неудачных архитектурных решений).
2) Посмотрите как это же приложение можно было сделать на Grails (там под капотом те же спринг и гибернейт, но кода всего строчек 100 будет, считая импорты)
Спасибо за перевод!
Впервые смотрел на Angular под таким «углом».
Много думал.

Information

Rating
Does not participate
Location
Новосибирск, Новосибирская обл., Россия
Date of birth
Registered
Activity