Предположим есть массив байт
byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
и вот такая
[StructLayout(LayoutKind.Explicit)]
struct ByteToUlongConverter
{
[FieldOffset(0)]
public byte[] bytes;
[FieldOffset(0)]
public ulong[] ulongs;
public ByteToUlongConverter(byte[] bytes)
{
this.ulongs = null;
this.bytes = bytes;
}
}
структура.
Далее с помощью этой структуры я делаю
ByteToUlongConverter conv = new ByteToUlongConverter(bytes);
foreach (ulong ul in conv.ulongs)
Console.WriteLine($"{ul:X16}");
При этом выводится что-то наподобие
0807060504030201
793C086C00000000
0000000000000000
0000000000000000
0000000000000000
0000000004710B40
00000001793BFDD8
793BED0C00000000
Т.е. выделял я 8 байт, а прочёл 64 (можно даже не только прочесть, но и записать что-то).
Вот эти дополнительные байты они чьи? Что это за память? Т.е. насколько я понимаю мой массив лежит где-то в куче, а это что-то, что лежит рядом. Куча в .Net как организована, она одна на все процессы или у каждого процесса своя куча? Т.е. может ли другой процесс без особых привилегий попытаться считать таким образом что-то в моём процессе?
Ответ
Вы правы, это память из кучи, расположенная сразу за массивом байт. Куча в .NET одна на каждый application domain, или, условно говоря, одна на одно приложение. Сборщик мусора работает именно с кучей, и было бы не очень хорошо, если из-за соседнего приложения пришлось бы останавливать также и ваше приложение, чтобы освободить память.
Однако обратите внимание, что процесс и домен приложения — разные понятия. Процесс это структура ядра Windows, и внутри одного процесса может быть множество доменов приложения, потому что они (предположительно) управляемые — то есть не могут просто так залезть в память друг друга. Но, поскольку это один процесс Windows то теоретически они конечно могут испортить память друг друга, если используют неуправляемый код.
Поэтому .NET не разрешает просто так запускать неуправляемый код (см. раздел Security в An Overview of Managed/Unmanaged Code Interoperability). Другой процесс точно не может залезть в вашу память из-за аппаратных ограничений, и другой домен приложения не сможет, если вы очень явно этого не разрешите.
Кстати, куча тоже не обычная последовательность блоков — для увеличения производительности сборки мусора, она разбита на две части: для маленьких объектов и для больших объектов.
Теперь конкретно про ваш код. Вы располагаете два массива по одному и тому же адресу. В .NET размер массива хранится в самом его начале, для него выделяется 8 байт, то есть число типа System.Int64. Исходный массив имеет длину 8. Когда вы пытаетесь работать с этим массивом, как с массивом ulong'ов, длина остаётся той же, то есть 8, но вот сами элементы становятся больше в 8 раз. Поэтому вы можете прочитать 8 × 8 байт вместо 8.
Но иногда может происходить исключение, связанное с тем, что массив проходит по границе сегмента, выделенного операционной системой, и это будет уже чисто аппаратное исключение. Если вы попытаетесь записать что-то в ulong массив, поведение будет непредсказуемым. Каждый блок в куче предваряется служебным заголовком, поэтому с 9-го байта может быть такой заголовок и расположен, соответственно при следующей сборке мусора приложение может упасть.
Комментариев нет:
Отправить комментарий