Удобная навигация по видео :) 0:00 - Начало 0:42 - Копирование данных в стеке 2:34 - Копирование данных в куче 4:51 - Производительность стека 8:00 - Ссылочные типы 10:59 - Технические характеристики стека и кучи 13:59 - Завершение
Рад, что информация оказалась полезной. Для самостоятельного изучения, рекомендую первоисточник от Microsoft: docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
благодаря этим визуализациям и подаче , я смог за 10минут написать пример из видео для структуры и класса и на практике узнать как эти два типа друг от друга отличаются , спасибо!
Держу за Вас кулачки 🤞 По работе с памятью, точно не должно быть пробелов 🙂 Кстати, если на собеседовании будут какие-то каверзные вопросы, пишите, обязательно рассмотрим на канале)
Можно было добавить еще один важный момент в примере с игрушками. Даже если в PlayWithToy передать toy по значению (не по ссылке) и закомментировать 19 строчку кода(создание нового объекта Toy на heap), то CreateToy вернет Пятачка.
@@codaza-channel возможно в данном вопросе Вам нужно проявить проактивный подход и все таки раскрыть эту тему. Думаю этим самым ВЫ привлечете еще бОльше посетителей и подписчиков! Спасибо за контент!
9:00 - изменение объекта класса возможно при передаче копии ссылки (т.е копия ссылки не запрещает вам менять поля объекта (собственно копия ссылки и не создает копию объекта как некотрым могло бы показаться), как кажется из видео, а мешает только изменить сам объект (допустим переинициализировать)), если не создавать новый объект. Т.е простыми словами копирование ссылки позволяет изменять объект хипа (поменяйте местами строчки кода Playwhittoy) и получите аналогичный результат что и с ref
Здравствуйте, отличные видео, спасибо за ваш труд. Из видео узнал про POH, возможно у вас получится доступно объяснить подробнее про эту часть Heap в отдельном видео?
До гигабайтов не дойдёт, размер стэка по дефолт - 1мб 😂 а дальше стэковерфлоу эксепшен. И стэк поинтер - это не совсем ссылка, по крайней мере не в памяти, это специальный регистр SP в процессоре
Спасибо большое за видео! Очень интересно и доходчиво. Скажите, пожалуйста, как конкретно отрабатывает сборщик мусора в стеке на примере вашего метода (2:17)? Если из стека мы берём сверху, то сначала должна удалится переменная orange и потом мы сможем сделать возврат значения переменной apple, или return apple не зависит от наличия в стеке переменной orange? И ещё: удаляется стек фрейм целиком или пошагово по одной переменной, в том порядке как и помещались переменные?
Екатерина, благодарю за отличный вопрос. Прежде всего стоит отметить, что сборщик мусора работает в куче. На стеке нет такого понятия как сборка мусора. Следующий момент, как таковое удаление данных на стеке не производится. Существует так называемый Stack Pointer (или указатель стека), который указывает на вершину стека. После того как метод завершает работу, Stack Pointer сдвигается вниз на значение стек фрейма. Данные в стеке остаются, просто они будут перезаписаны другими данными, когда потребуется выделение памяти на стеке для размещения очередной переменной, например.
Благодарю за комментарий. Рад, что информация в ролике оказалась полезной. Касательно POH. Подскажите, пожалуйста, на какой временной отметке в ролике Вы услышали "pick"?
4:04 - указатель не копируется. В это время создается новый указатель (oranges), который указывает на область памяти NULL. После oranges = apples новому созданному указателю присваивается адрес apples. И он начинает ссылаться на туже область памяти, что и apples
То есть копируется ссылка. Автор так и сказал. И "область памяти NULL"(с) не существует. null - значение предоставляющее пустую ссылку, то есть отсутствие области в памяти, а не какую-то NULL-область.
Вторая часть уступает первой. Особенно "Технические характеристики" не очень расписаны. Важные детали, например, когда определяется размер выделяемой памяти для переменной и её конкретный тип, почему в результате этих различий куча делает возможным использование полиморфизма. Зато упомянуты не такие фундаментальные детали как local/global и Stack pointer. Хуже всего, что упомянуты совсем в скользь, что делает эту информацию околобесполезной, а если упомянуть на собеседовании, то следующие за этим уточняющие вопросы посадят в лужу. И на практике бесполезно, если знать одни названия. И размер по умолчанию (1мб) тоже какая-то околобесполезная и очень специфическая информация. Лучше совсем такое не упоминать, если не погружаться в детали. SOH-LOH-POH, еще статическую кучу где-то потеряли. Тоже бесполезная информация. Уже лучше бы рассказали тогда про особенности работы GC, почему не очень хорошо создавать "большие" объекты и как они могут приводить к потерям памяти и т.д. Короче, слабовато.
На самом деле не будет. Мы просто потеряем на него ссылку. И если в процессе будет вызван Garbage Collector, то он пометит Винни как свободную память. И, возможно, в дальнейшем "свободная" память будет заполнена новыми данными.
на 4:26 можно ли сказать, что мы скопировали именно корзинку с предметами внутри, и передали общее количество предметов в обеих корзинках в Basket ? Для понимания
Нет, это неверно. Корзинка (Basket) в оперативной памяти всегда одна и количество предметов в ней одно (ItemsCount). А вот ссылок, указывающих на корзинку - две. Сначала была одна ссылка, потом мы её скопировали и получили 2 ссылки, но обе они ссылаются на одну и ту же корзинку.
а как будет выглядеть размещение переменных в стеке, которые объявлены уже внутри вызываемого метода? К примеру, есть for цикл, внутри которого вызывается некий делегат или поток с лямбда-функцией. Чтобы эти делегаты не шарили общую переменную, которая объявлена в скобках for, нужно объявить доп переменую уже в теле for. Как в этом случаи выделяется память? формируется ли стек фрейм при каждой итерации for? Спасибо!
Вы задали очень интересный вопрос. Я отвечу на первую часть вопроса, а по второй попрошу уточнений, так как не совсем понял, что вы имеете ввиду. По первой части вопроса. Выделение памяти на стеке происходит очень логично: Увидели объявление переменной? Положили значение на стек. Переменная находится за пределами области видимости? Убрали значение со стека. Таким образом, объявляя переменную внутри цикла For, мы располагаем её значение на стеке (в рамках выделенного стекфрейма). Выполняя очередную итерацию цикла For, предыдущее значение переменной будет удалено со стека, так как будет находиться за пределами области видимости (мы на новой итерации). По второй части вопроса. Сначала небольшая ремарка: У каждого потока свой стек. То есть, если у нас будет 10 потоков, у нас будет 10 стеков. Вот тут я не понял, что вы имеете ввиду: "Чтобы эти делегаты не шарили общую переменную, которая объявлена в скобках for, нужно объявить доп переменую уже в теле for" Приведите, пожалуйста, пример кода и тогда, я постараюсь дать более подробный ответ.
На 2:31 вы сказали что значение из apples копируется в oranges, но как это происходит, ведь мы можем читать только вершину стека, а apples не на вершине. Допустим мы в конце метода добавим еще int bananas = apples. В бананы скопируется значение яблок, но ведь apples не на вершине стека. Буду рад если уточните этот вопрос)
Здесь важно понимать, что "Обращение к данным в стеке" и "Извлечение данных из стека" - не одно и тоже. Мы можем производить обращение к данным в стеке без извлечения этих данных из него. Вас же не смущает, что мы можем обратиться к параметрам метода из любого места метода? 🙂 Извлечение данных из стека применяется при выходе переменной из области видимости (например, при завершении тела цикла). После извлечения данных из стека, они становятся недоступными для дальнейших обращений.
Такой вопрос. В структуре объявлено поле типа MyClass. Правильно я понимаю, что когда будет создан экземпляр данной структуры , экземпляр MyClass будет лежать на стеке?
Нет, MyClass всё еще является ссылочным типом, несмотря на то, что находится внутри структуры. Экземпляр класса MyClass будет размещен в куче, а на стеке будет храниться ссылка на него.
размер стек фрейма определяется типом переменных. наверное есть некая область переменных, из которой они, переменные, попадают в конкретный фрейм. Как определяется эта область (к примеру, под один метод выделяется один фрейм)?
Стек фрейм определяется при вызове метода. То есть перед началом выполнения тела метода, на стеке определяется место, в котором располагается информация о параметрах метода + служебная информация (например, адреса возвратов). Вследствие чего, происходит смещение указателя стека.
@@codaza-channel клево, спасибо! еще такой был вопрос, для чего еще придумали кучу, если стек работает быстро. Связано ли это с тем, что стек работать как фифо, а к объекту в куче можно обратиться по адресу? Есть ли ограничения фрейма стека?
@shurale85 Стек работает быстро, потому что он имеет небольшой размер (1 MB) и работает по принципу LIFO (нужные данные всегда на вершине стека). Куча, в свою очередь, даёт нам память ограниченную лишь ресурсами физической машины и возможность произвольного доступа к данным по адресам в памяти, которые располагаются на стеке. Касательно размера стек фрейма, он ограничен размером стека.
Да, размер Heap действительно имеет ограничение в 32-разрядных системах и составляет приблизительно 1.5 Гб. Другой вопрос, как часто вам приходится пользоваться 32-разрядными системами в 2022 году? 🙂
Если Вы передаете в качестве параметров простые типы (int, bool и т. д.), то в этом точно нет проблемы. Если вы передаёте структуры, то тут нужно рассматривать каждый случай индивидуально, так как даже небольшие структуры передаваемые по значению, но часто, могут создавать проблемы производительности.
Артём, спасибо за вопрос. В .NET существует так называемая Common Language Runtime (англ. CLR - общеязыковая исполняющая среда). Не вдаваясь во все сложности, можно сказать, что CLR это мини операционная система, которая много чего умеет и всегда находится рядом с вашей программой написанной на C#. Именно CLR принимает решение о том, где данные будут расположены - на стеке или в куче.
Как раз об этом мы подробно говорим в роликах, посвященных работе памяти 😊 Если очень-очень коротко: Значимые типы располагаются на стеке, а ссылочные в куче. Это не всегда так, но для quick start самое лучшее определение. Еще важно понимать, что стек - быстрый, а куча - медленная. Поэтому это имеет свое влияние на производительность. Если вы совсем-совсем новичок, я бы рекомендовал вам вернуться к вопросам работы с памятью позже. Не забивайте себе голову этими вещами сейчас. В начале пути лучше сосредоточиться на синтаксисе языка, попробовать что-то сделать самостоятельно (хотя бы калькулятор), повыводить что-нибудь на консоль и т. д. Вы почувствуете, когда придёт время разбираться со стеком и кучей 😉
Чтобы понять в принципе, что такое стек и куча, а не как она работает в C#, советую начать с самого обычного C. Там придется вручную управлять памятью и через этот процесс можно лучше понять, что вообще происходит в памяти в любой программе на любом языке. Просто в таких языках как C# этот процесс частично происходит под капотом, в C все открыто и наглядно, более того там без понимания принципов работы с памятью - никак.
Удобная навигация по видео :)
0:00 - Начало
0:42 - Копирование данных в стеке
2:34 - Копирование данных в куче
4:51 - Производительность стека
8:00 - Ссылочные типы
10:59 - Технические характеристики стека и кучи
13:59 - Завершение
Здравствуйте! В какой программе вы делаете такую инфографика?
Здравствуйте! В PowerPoint.
Лучшее объяснение что я когда либо видел по данному вопросу. Спасибо автору! Рад был бы увидеть ссылки на источники для самостоятельного изучения
Рад, что информация оказалась полезной. Для самостоятельного изучения, рекомендую первоисточник от Microsoft: docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
После просмотра видео возникает чувство несправедливости : такая шикарная подача, но так мало подписчиков...
Шикарные 2 видео по стеку/куче. Спасибо за визуализацию, очень помогла понять что к чему.
Потрясающее видео, буквально на первых секундах подписалась. Спасибо за качественный контент!
Пожалуйста 🙂 Вам спасибо за комментарий и подписку. Очень рад, что контент нравится!
благодаря этим визуализациям и подаче , я смог за 10минут написать пример из видео для структуры и класса и на практике узнать как эти два типа друг от друга отличаются , спасибо!
Шикарное объяснение и разъяснение! Низкий поклон автору
Прекрасные видео! Дает 100% понимание сути стека, кучи, и их взаимоотношений. Спасибо!!!!
спасибо за детальное объяснение материала + ещё и визуализация. Наконец-то понял как всё работает. Автору респект!
Слишком идеальный tutor для 3000 подписчиков,желаю удачи !
супер понятный ролик!
Шикарні відео! Дуже дякую!)
лучше любих курсов!!
Очень интересно и понятно описано)
Супер объяснение! Очень наглядно и информативно))Спасибо)Ждем новых видео)
Алина, спасибо за комментарий. Рад, что ролик оказался информативным! Не забудьте про 3-ю часть (garbage collector) 🙂
@@codaza-channel Я посмотрела все части))Завтра собеседование))
Держу за Вас кулачки 🤞 По работе с памятью, точно не должно быть пробелов 🙂 Кстати, если на собеседовании будут какие-то каверзные вопросы, пишите, обязательно рассмотрим на канале)
Отличные уроки! Лайк, шер, подписка - однозначно!
Можно было добавить еще один важный момент в примере с игрушками. Даже если в PlayWithToy передать toy по значению (не по ссылке) и закомментировать 19 строчку кода(создание нового объекта Toy на heap), то CreateToy вернет Пятачка.
Отличное видео, все очень наглядно. Лайк, подписка!
Жаль, что с Винни-Пухом так вышло.. Контент отличный!
Бедный Винни Пух
Спасибо большое за ваш труд! Очень помогло))
Супер объяснение!
Супер! Спасибо
Спасибо, ты сделал мой день!
Спасибо!
проорал с POH :)
Тему асинхронщины будете раскрывать? ) async/await, tpl, valuetask, когда уместно использование асинк операций, а когда нет..
Если это будет интересно, обязательно поговорим об этом на канале. Вы пока первый, кто попросил об этом 🙂
@@codaza-channel возможно в данном вопросе Вам нужно проявить проактивный подход и все таки раскрыть эту тему. Думаю этим самым ВЫ привлечете еще бОльше посетителей и подписчиков! Спасибо за контент!
красава
9:00 - изменение объекта класса возможно при передаче копии ссылки (т.е копия ссылки не запрещает вам менять поля объекта (собственно копия ссылки и не создает копию объекта как некотрым могло бы показаться), как кажется из видео, а мешает только изменить сам объект (допустим переинициализировать)), если не создавать новый объект. Т.е простыми словами копирование ссылки позволяет изменять объект хипа (поменяйте местами строчки кода Playwhittoy) и получите аналогичный результат что и с ref
Здравствуйте, отличные видео, спасибо за ваш труд.
Из видео узнал про POH, возможно у вас получится доступно объяснить подробнее про эту часть Heap в отдельном видео?
Благодарю за положительный комментарий. Если тема будет интересна, я думаю мы сможем поговорить об этом в отдельном ролике 🙂
@@codaza-channel конечно, будете первым, кто в Руском сегменте объяснил это новшество:)
До гигабайтов не дойдёт, размер стэка по дефолт - 1мб 😂 а дальше стэковерфлоу эксепшен. И стэк поинтер - это не совсем ссылка, по крайней мере не в памяти, это специальный регистр SP в процессоре
супер
винни пуха жалко((
Спасибо большое за видео! Очень интересно и доходчиво. Скажите, пожалуйста, как конкретно отрабатывает сборщик мусора в стеке на примере вашего метода (2:17)? Если из стека мы берём сверху, то сначала должна удалится переменная orange и потом мы сможем сделать возврат значения переменной apple, или return apple не зависит от наличия в стеке переменной orange? И ещё: удаляется стек фрейм целиком или пошагово по одной переменной, в том порядке как и помещались переменные?
Екатерина, благодарю за отличный вопрос. Прежде всего стоит отметить, что сборщик мусора работает в куче. На стеке нет такого понятия как сборка мусора. Следующий момент, как таковое удаление данных на стеке не производится. Существует так называемый Stack Pointer (или указатель стека), который указывает на вершину стека. После того как метод завершает работу, Stack Pointer сдвигается вниз на значение стек фрейма. Данные в стеке остаются, просто они будут перезаписаны другими данными, когда потребуется выделение памяти на стеке для размещения очередной переменной, например.
Хорошее видео, но звук перехода с одного раздела на другой очень резкий и бьёт по ушам
спасибо, классное и наглядное объяснение. Только пох - это pinned object heap (not pick).
Благодарю за комментарий. Рад, что информация в ролике оказалась полезной.
Касательно POH. Подскажите, пожалуйста, на какой временной отметке в ролике Вы услышали "pick"?
@@codaza-channel дважды прослушала, вроде пик)) ну ладно, может, там было и пиннд)))
@@evagor730 пинд-пинд))
больше примеров! спасибо
4:04 - указатель не копируется. В это время создается новый указатель (oranges), который указывает на область памяти NULL. После oranges = apples новому созданному указателю присваивается адрес apples. И он начинает ссылаться на туже область памяти, что и apples
То есть копируется ссылка. Автор так и сказал.
И "область памяти NULL"(с) не существует. null - значение предоставляющее пустую ссылку, то есть отсутствие области в памяти, а не какую-то NULL-область.
Автор сделай пожалуйста видео про CLR в своем стиле, будет интересно
Вторая часть уступает первой. Особенно "Технические характеристики" не очень расписаны. Важные детали, например, когда определяется размер выделяемой памяти для переменной и её конкретный тип, почему в результате этих различий куча делает возможным использование полиморфизма. Зато упомянуты не такие фундаментальные детали как local/global и Stack pointer. Хуже всего, что упомянуты совсем в скользь, что делает эту информацию околобесполезной, а если упомянуть на собеседовании, то следующие за этим уточняющие вопросы посадят в лужу. И на практике бесполезно, если знать одни названия. И размер по умолчанию (1мб) тоже какая-то околобесполезная и очень специфическая информация. Лучше совсем такое не упоминать, если не погружаться в детали. SOH-LOH-POH, еще статическую кучу где-то потеряли. Тоже бесполезная информация. Уже лучше бы рассказали тогда про особенности работы GC, почему не очень хорошо создавать "большие" объекты и как они могут приводить к потерям памяти и т.д.
Короче, слабовато.
"Сборщик мусора удаляет Пятачка при первой возможности"......
😥
Что будет с Винни Пухом ? Нечего хорошего. Он будет уничтожен!
На самом деле не будет. Мы просто потеряем на него ссылку. И если в процессе будет вызван Garbage Collector, то он пометит Винни как свободную память. И, возможно, в дальнейшем "свободная" память будет заполнена новыми данными.
на 4:26 можно ли сказать, что мы скопировали именно корзинку с предметами внутри, и передали общее количество предметов в обеих корзинках в Basket ? Для понимания
Нет, это неверно. Корзинка (Basket) в оперативной памяти всегда одна и количество предметов в ней одно (ItemsCount). А вот ссылок, указывающих на корзинку - две. Сначала была одна ссылка, потом мы её скопировали и получили 2 ссылки, но обе они ссылаются на одну и ту же корзинку.
а как будет выглядеть размещение переменных в стеке, которые объявлены уже внутри вызываемого метода? К примеру, есть for цикл, внутри которого вызывается некий делегат или поток с лямбда-функцией. Чтобы эти делегаты не шарили общую переменную, которая объявлена в скобках for, нужно объявить доп переменую уже в теле for. Как в этом случаи выделяется память? формируется ли стек фрейм при каждой итерации for? Спасибо!
Вы задали очень интересный вопрос. Я отвечу на первую часть вопроса, а по второй попрошу уточнений, так как не совсем понял, что вы имеете ввиду.
По первой части вопроса. Выделение памяти на стеке происходит очень логично:
Увидели объявление переменной? Положили значение на стек.
Переменная находится за пределами области видимости? Убрали значение со стека.
Таким образом, объявляя переменную внутри цикла For, мы располагаем её значение на стеке (в рамках выделенного стекфрейма). Выполняя очередную итерацию цикла For, предыдущее значение переменной будет удалено со стека, так как будет находиться за пределами области видимости (мы на новой итерации).
По второй части вопроса. Сначала небольшая ремарка: У каждого потока свой стек. То есть, если у нас будет 10 потоков, у нас будет 10 стеков.
Вот тут я не понял, что вы имеете ввиду:
"Чтобы эти делегаты не шарили общую переменную, которая объявлена в скобках for, нужно объявить доп переменую уже в теле for"
Приведите, пожалуйста, пример кода и тогда, я постараюсь дать более подробный ответ.
На 2:31 вы сказали что значение из apples копируется в oranges, но как это происходит, ведь мы можем читать только вершину стека, а apples не на вершине. Допустим мы в конце метода добавим еще int bananas = apples. В бананы скопируется значение яблок, но ведь apples не на вершине стека. Буду рад если уточните этот вопрос)
Здесь важно понимать, что "Обращение к данным в стеке" и "Извлечение данных из стека" - не одно и тоже. Мы можем производить обращение к данным в стеке без извлечения этих данных из него. Вас же не смущает, что мы можем обратиться к параметрам метода из любого места метода? 🙂
Извлечение данных из стека применяется при выходе переменной из области видимости (например, при завершении тела цикла). После извлечения данных из стека, они становятся недоступными для дальнейших обращений.
@@codaza-channel спасибо большое, теперь вижу разницу
SOH LOH POH
может быть не ref ,а in ? Я прост не слишком шарю.
Такой вопрос. В структуре объявлено поле типа MyClass. Правильно я понимаю, что когда будет создан экземпляр данной структуры , экземпляр MyClass будет лежать на стеке?
Нет, MyClass всё еще является ссылочным типом, несмотря на то, что находится внутри структуры. Экземпляр класса MyClass будет размещен в куче, а на стеке будет храниться ссылка на него.
@@codaza-channel thank you
размер стек фрейма определяется типом переменных. наверное есть некая область переменных, из которой они, переменные, попадают в конкретный фрейм. Как определяется эта область (к примеру, под один метод выделяется один фрейм)?
Стек фрейм определяется при вызове метода. То есть перед началом выполнения тела метода, на стеке определяется место, в котором располагается информация о параметрах метода + служебная информация (например, адреса возвратов). Вследствие чего, происходит смещение указателя стека.
@@codaza-channel клево, спасибо! еще такой был вопрос, для чего еще придумали кучу, если стек работает быстро. Связано ли это с тем, что стек работать как фифо, а к объекту в куче можно обратиться по адресу? Есть ли ограничения фрейма стека?
@shurale85 Стек работает быстро, потому что он имеет небольшой размер (1 MB) и работает по принципу LIFO (нужные данные всегда на вершине стека). Куча, в свою очередь, даёт нам память ограниченную лишь ресурсами физической машины и возможность произвольного доступа к данным по адресам в памяти, которые располагаются на стеке. Касательно размера стек фрейма, он ограничен размером стека.
А разве Heap неограничен по размерам только для х64, а в х32 потолок таки есть?
Да, размер Heap действительно имеет ограничение в 32-разрядных системах и составляет приблизительно 1.5 Гб. Другой вопрос, как часто вам приходится пользоваться 32-разрядными системами в 2022 году? 🙂
@@codaza-channel , это да. Просто подумал, что нелишним будет упомянуть про различие в работе с разной архитектурой)
зачастую в методы передаются значения, вместо ссылки, получается это все же не так страшно в большинстве случаев?
Если Вы передаете в качестве параметров простые типы (int, bool и т. д.), то в этом точно нет проблемы. Если вы передаёте структуры, то тут нужно рассматривать каждый случай индивидуально, так как даже небольшие структуры передаваемые по значению, но часто, могут создавать проблемы производительности.
пяточка жалко... 9:50
😢
Я новичок, у меня возник вопрос.
Кто решает как будут храниться данные, в стеке или в куче?
Артём, спасибо за вопрос. В .NET существует так называемая Common Language Runtime (англ. CLR - общеязыковая исполняющая среда). Не вдаваясь во все сложности, можно сказать, что CLR это мини операционная система, которая много чего умеет и всегда находится рядом с вашей программой написанной на C#. Именно CLR принимает решение о том, где данные будут расположены - на стеке или в куче.
@@codaza-channel Cпасибо за ответ! А скажите пожалуйста, на основании чего идет выбор использовать стек или кучу?
Как раз об этом мы подробно говорим в роликах, посвященных работе памяти 😊 Если очень-очень коротко: Значимые типы располагаются на стеке, а ссылочные в куче. Это не всегда так, но для quick start самое лучшее определение. Еще важно понимать, что стек - быстрый, а куча - медленная. Поэтому это имеет свое влияние на производительность.
Если вы совсем-совсем новичок, я бы рекомендовал вам вернуться к вопросам работы с памятью позже. Не забивайте себе голову этими вещами сейчас. В начале пути лучше сосредоточиться на синтаксисе языка, попробовать что-то сделать самостоятельно (хотя бы калькулятор), повыводить что-нибудь на консоль и т. д.
Вы почувствуете, когда придёт время разбираться со стеком и кучей 😉
Чтобы понять в принципе, что такое стек и куча, а не как она работает в C#, советую начать с самого обычного C. Там придется вручную управлять памятью и через этот процесс можно лучше понять, что вообще происходит в памяти в любой программе на любом языке. Просто в таких языках как C# этот процесс частично происходит под капотом, в C все открыто и наглядно, более того там без понимания принципов работы с памятью - никак.
@@phat80 спасибо за совет, так и поступлю :)
А насчёт копирования данных в куче вопрос. А как тогда сделать, чтобы копировались сами данные, а не ссылки на них?
Здравствуйте, могу бесплатно обрабатывать ваш голос эквализатором, чтоб его было слышно лучше, так как это в моих интересах. Напишите мне!
Здравствуйте! Благодарю за предложенную помощь. В последних роликах на канале звук более ровный 🙂
@@codaza-channel Хорошо, но предложение будет в силе ! Спасибо за простую подачу достаточно ёмкого и сложного материала.
💙
Жаль, конечно, этого винни пуха
Музыка ужасная. Скулы сводит. Урок хорош.
9:55 Пяточка жалко(