Проблемы с производительностью Android (Java)? - PullRequest
0 голосов
/ 18 октября 2011

Я недавно начал писать 2D-приложение для Android (чистый Java-код).У меня нет значительного опыта программирования на Java и Android.

У меня очень плохая производительность моего Java-кода.Это кажется странным, так как телефон, который я использую, представляет собой Samsung Glaxy S2 (двухъядерный процессор ARM Cortex A9, 1,2 ГГц), который должен давать гораздо лучшие результаты.

Мое приложение - это живые обои.Я использую библиотеку android.graphics для рисования своих изображений.Я использую пользовательский код графа сцены для управления своими преобразованиями и ограничивающей прямоугольной иерархией (я также делаю тестирование видимости).

Согласно профилировщику DDMS (трассировка метода), мой цикл рендеринга выполняется в течение 30 - 45 мс(не знаю, почему это так сильно меняется, поскольку моя сцена не меняется от захвата к захвату).

Растровое рисование занимает около 15 мс.Оставшееся время (15-30 мс) тратится на прохождение графа сцены для обновления преобразований и проверки видимости.

У меня 12 узлов и 11 прорисовываемых объектов в графе сцены!

Я действительно могуне понимаю, почему код работает так медленноИз DDMS я не могу определить какую-либо конкретную часть кода, которая является узким местом.У меня нет временных объектов, выделенных в коде, кроме тонны итераторов, от которых я не могу найти способ избавиться.

Кажется, что просто вызов методов занимает ОДНО времени.30 мс - это много для обхода 12 узлов и умножения их матриц вместе + расширения некоторых рядов.

1,6 мс для сортировки 4-5 объектов ???

Я должен делать что-то действительно глупое!Любые предложения будут высоко оценены!

private final LinkedList<SceneNode> m_children  = new LinkedList<SceneNode>();
private final LinkedList<Drawable>  m_drawables = new LinkedList<Drawable>();

public void update(boolean updateChildren)
{
    updateDerivedTransform();

    if (updateChildren)
    {
        for (SceneNode child : m_children)
        {
            child.update(updateChildren);
        }
    }

    updateBoundingRect();
}
protected void updateDerivedTransform()
{
    if (m_parent != null)
    {
        m_derivedTransform.setConcat(m_parent.m_derivedTransform, m_transform);
    }
    else
    {
        m_derivedTransform.set(m_transform);
    }
}
public void updateBoundingRect()
{
    m_boundingRect.setEmpty();

    for (Drawable drawable : m_drawables)
    {
        m_boundingRect.union(drawable.getTransformedBoundingRect());
    }

    for (SceneNode child : m_children)
    {
        m_boundingRect.union(child.m_boundingRect);
    }
}
public void findVisibleObjects(RectF viewRect, DrawQueue queue, boolean includeChildren, boolean addNodes)
{
    float x = m_boundingRect.left;
    float y = m_boundingRect.top;
    float w = m_boundingRect.right;
    float h = m_boundingRect.bottom;

    if (viewRect.contains(x, y, w, h) || viewRect.intersects(x, y, w, h))
    {
        queue.getContainer().addAll(m_drawables);

        for (SceneNode child : m_children)
        {
            child.findVisibleObjects(viewRect, queue, includeChildren, addNodes);
        }
    }
}

Большое спасибо за вашу помощь!

Ответы [ 3 ]

2 голосов
/ 18 октября 2011

Вот несколько мыслей, не видя ваш код.

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

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

Тем не менее, если мы сможем увидеть код, возможно, мы сможем указать на те моменты в коде, которые особенно неэффективны и могут быть улучшены.

0 голосов
/ 18 октября 2011

В Java много накладных расходов, особенно в реализации Android (в dalvik).Постарайтесь уменьшить количество вызовов, которые вы совершаете между классами, особенно.

В качестве незначительной оптимизации (когда вы достигаете этой точки) вместо использования LinkedList рассмотрите возможность использования ArrayList (или дажемассив статического размера, если вы не часто добавляете элементы) и делаете это для своего цикла:

final int count = m_drawables.size();
for (int i = 0; i < count; i++) {
    Drawable drawable = m_drawables.get(i);
    //...
}

JIT Android действительно плохо оптимизирует циклы итератора контейнера (for (Foo foo : fooContainer)), и я обнаружилдовольно большие ускорения путем преобразования их в традиционные подсчитанные циклы.Если вы посмотрите на дизассемблирование кода, такие циклы фактически превращаются в ОГРОМНОЕ количество вызовов методов с большим количеством создания и уничтожения объектов для итератора.Они удобны для экономии кода, но не для повышения производительности (хотя, надеюсь, в этом помогут будущие улучшения JIT от Dalvik).

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

0 голосов
/ 18 октября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...