Warning: mkdir(): No space left on device in /var/www/tgoop/post.php on line 37

Warning: file_put_contents(aCache/aDaily/post/csharp_gepard/--): Failed to open stream: No such file or directory in /var/www/tgoop/post.php on line 50
C# Heppard@csharp_gepard P.139
CSHARP_GEPARD Telegram 139
Аллокация объектов на стеке #память

Наверное, многие слышали, что .NET 9 теперь старается не размещать короткоживущие объекты в куче, если они являются boxed value-типами. Теперь результат "боксинга" таких типов располагается на стеке, что позволяет разгрузить GC и увеличить производительность.

Конечно же, есть "но". Дело в том, что runtime должен быть уверен, что результат боксинга не выходит за границы метода. В этом и только в этом случае, результат боксинга value-типа (фактически object) будет располагаться на стеке. Это очень похоже на Rust, где есть встроенная в язык функция наблюдения за временем жизни переменной. Выход из метода "удаляет" все сущности, которые были созданы внутри него, но не используются вне него.

В примере ниже, как и раньше до .NET 9, произойдёт боксинг цифр "3" и "4" при вызове метода Compare. Однако runtime (JIT) "видит", что эти объекты не выходят за пределы метода RunIt. Следовательно, результат боксинга можно разместить на стеке.

static bool Compare(object? x, object? y)
{
if (x == null || y == null)
{
return x == y;
}

return x.Equals(y);
}

public static int RunIt()
{
bool result = Compare(3, 4);
return result ? 0 : 100;
}


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

var result = 0;
foreach ((int a, int b) in _values)
{
result += Compare(a, b) ? 1 : -1;
}
return result;


Дело в том, что в конкретно этом случае, по мнению JIT, в методе может быть создано слишком много "забокшеных" value-типов, что, в свою очередь, значит, что оптимизация применена не будет.

Есть и иное предположение. Оно основано на том, что функция Compare принимает, условно, всё, что угодно. Это, в свою очередь, значит, что JIT справедливо полагает: размер данных в аргументах функции может быть разным на любой итерации for. А это означает, что невозможно вызывать Compare с уравниванием всех возможных типов аргументов по размеру (см. вот этот комментарий).

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

bool CloseContext(int a, int b) => Compare(a, b);


Но, увы, это не сработает, так как в дело включается другая оптимизация - method inlining. Для JIT'a этот метод - прекрасный случай для автоматического инлайнинга. Увы, это ломает нашу прекрасную идею с обозначением контекста, в рамках которого будут жить наши boxed value-типы.

Значит, мы должны не только создать отдельный метод, но и прямо указать, что делать ему "инлайн" не нужно. Благо, у нас есть специальный атрибут для подобных указаний - [MethodImpl(MethodImplOptions.NoInlining)]. В этом случае, боксинг происходит, но его результат остаётся на стеке. Результаты хорошо видны на бенчмарке.

Код бенчмарка тут. Если нужно больше подробностей, то я написал этот пост под впечатлениями вот отсюда.
👍37🔥17👎1



tgoop.com/csharp_gepard/139
Create:
Last Update:

Аллокация объектов на стеке #память

Наверное, многие слышали, что .NET 9 теперь старается не размещать короткоживущие объекты в куче, если они являются boxed value-типами. Теперь результат "боксинга" таких типов располагается на стеке, что позволяет разгрузить GC и увеличить производительность.

Конечно же, есть "но". Дело в том, что runtime должен быть уверен, что результат боксинга не выходит за границы метода. В этом и только в этом случае, результат боксинга value-типа (фактически object) будет располагаться на стеке. Это очень похоже на Rust, где есть встроенная в язык функция наблюдения за временем жизни переменной. Выход из метода "удаляет" все сущности, которые были созданы внутри него, но не используются вне него.

В примере ниже, как и раньше до .NET 9, произойдёт боксинг цифр "3" и "4" при вызове метода Compare. Однако runtime (JIT) "видит", что эти объекты не выходят за пределы метода RunIt. Следовательно, результат боксинга можно разместить на стеке.

static bool Compare(object? x, object? y)
{
if (x == null || y == null)
{
return x == y;
}

return x.Equals(y);
}

public static int RunIt()
{
bool result = Compare(3, 4);
return result ? 0 : 100;
}


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

var result = 0;
foreach ((int a, int b) in _values)
{
result += Compare(a, b) ? 1 : -1;
}
return result;


Дело в том, что в конкретно этом случае, по мнению JIT, в методе может быть создано слишком много "забокшеных" value-типов, что, в свою очередь, значит, что оптимизация применена не будет.

Есть и иное предположение. Оно основано на том, что функция Compare принимает, условно, всё, что угодно. Это, в свою очередь, значит, что JIT справедливо полагает: размер данных в аргументах функции может быть разным на любой итерации for. А это означает, что невозможно вызывать Compare с уравниванием всех возможных типов аргументов по размеру (см. вот этот комментарий).

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

bool CloseContext(int a, int b) => Compare(a, b);


Но, увы, это не сработает, так как в дело включается другая оптимизация - method inlining. Для JIT'a этот метод - прекрасный случай для автоматического инлайнинга. Увы, это ломает нашу прекрасную идею с обозначением контекста, в рамках которого будут жить наши boxed value-типы.

Значит, мы должны не только создать отдельный метод, но и прямо указать, что делать ему "инлайн" не нужно. Благо, у нас есть специальный атрибут для подобных указаний - [MethodImpl(MethodImplOptions.NoInlining)]. В этом случае, боксинг происходит, но его результат остаётся на стеке. Результаты хорошо видны на бенчмарке.

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

BY C# Heppard




Share with your friend now:
tgoop.com/csharp_gepard/139

View MORE
Open in Telegram


Telegram News

Date: |

Unlimited number of subscribers per channel The imprisonment came as Telegram said it was "surprised" by claims that privacy commissioner Ada Chung Lai-ling is seeking to block the messaging app due to doxxing content targeting police and politicians. Matt Hussey, editorial director at NEAR Protocol also responded to this news with “#meIRL”. Just as you search “Bear Market Screaming” in Telegram, you will see a Pepe frog yelling as the group’s featured image. Write your hashtags in the language of your target audience. With the “Bear Market Screaming Therapy Group,” we’ve now transcended language.
from us


Telegram C# Heppard
FROM American