Каковы последствия производительности передачи структур в массиве по ссылке в C # - PullRequest
4 голосов
/ 16 декабря 2009

Я работаю над фрагментом кода в C # / XNA, где я очень обеспокоен производительностью. Частично это передает несколько структур, которые хранятся в массивах, различным функциям.

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

Я уже немного улучшил производительность, передав по ссылке, но мне интересно, как это влияет на производительность, когда одна и та же структура с одним и тем же индексом массива передается нескольким различным функциям по ссылке. Я предполагаю, что для того, чтобы все это работало, C # должен внутренне закрепить указатель массива перед передачей структуры. Получу ли я производительность, закрепив структуру сначала и передав указатель вместо нее?

Например. Если у меня есть что-то вроде:

for(int i = 0; i < array.Length; ++i)
{
    value = Function1(ref array[i]);

    // Lots of code....

    otherValue = Function2(ref array[i]);

    // Lots of code....

    anotherValue = Function3(ref array[i]);
}

Разве C # по сути не должен это делать?

for(int i = 0; i < array.Length; ++i)
{
    pin(array);
    value = Function1(ref array[i]);
    unpin(array);

    // Lots of code....

    pin(array);
    otherValue = Function2(ref array[i]);
    unpin(array);

    // Lots of code....

    pin(array);
    anotherValue = Function3(ref array[i]);
    unpin(array);
}

И было бы мне лучше сделать это?

for(int i = 0; i < array.Length; ++i)
{
    fixed(struct* working = ^array[i]) 
    {
        value = Function1(working);

        // Lots of code....

        otherValue = Function2(working);

        // Lots of code....

        anotherValue = Function3(working);
    }
}

Или, еще лучше,

fixed(struct* working = ^array[0]) 
{
    for(int i = 0; i < array.Length; ++i)
    {
        value = Function1(working[i]);

        // Lots of code....

        otherValue = Function2(working[i]);

        // Lots of code....

        anotherValue = Function3(working[i]);
    }
}

Или компилятор C # / JITter достаточно умен, чтобы автоматически закрепить массив?

Ответы [ 2 ]

11 голосов
/ 16 декабря 2009

Вы путаете управляемые ссылки с указателями.

Управляемая ссылка никогда не нуждается в закреплении, даже если она указывает на элемент в массиве, потому что GC «знает» о ссылке и обновит ее, если массив будет перемещен.

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

0 голосов
/ 16 декабря 2009

Я не уверен насчет XNA (это другой CLR), но .NET Framework (начиная с 3.5) не закрепляет вещи, передаваемые по ссылке (по умолчанию, если они не передаются в неуправляемый код. Если GC вызывается, он все еще может перемещать данные, так как в стеке проверяются ссылки. Если на каком-то уровне происходит неуправляемый код, то да, его действительно нужно закрепить.

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