public void freeing_the_list_frees_all_chunks() { // Setup, and allocate a load of entries var memsize = Mega.Bytes(1); var mem = new MemorySimulator(memsize); var alloc = new Allocator(0, memsize, mem); var subject = new Vector <SampleElement>(alloc, mem); int full = (int)(Allocator.ArenaSize / sizeof(long)) * 2; var expected = (full * 8) + ((full / 32) * 8); Console.WriteLine("Expecting to allocate " + expected); if (expected >= memsize) { Assert.Fail("memsize is not big enough for the test"); } for (int i = 0; i < full; i++) { subject.Push(Sample(i)); } // Now free the whole list at once (including base ptr) subject.Deallocate(); // check we've emptied memory alloc.GetState(out var allocatedBytes, out _, out var post_occupied, out _, out var post_refCount, out _); Assert.That(allocatedBytes, Is.Zero, "Expected no bytes allocated"); Assert.That(post_occupied, Is.Zero, "Expected no arenas occupied"); Assert.That(post_refCount, Is.Zero, "Expected no references"); }
public void running_a_scan_when_any_pointers_are_referenced_keeps_the_arena() { // scan takes a list of known references, and assumes anything // that's not in the list in not referenced. Any arena with nothing // referenced is reset. var mem = new MemorySimulator(Mega.Bytes(1)); var bump = (Allocator.ArenaSize / 4) + 1; // three fit in each arena, with some spare var subject = new Allocator(512, Mega.Bytes(1), mem); var x1 = subject.Alloc(bump).Value; var ar1 = subject.CurrentArena(); subject.Alloc(bump); subject.Alloc(bump); // fill up first arena var x2 = subject.Alloc(bump).Value; var ar2 = subject.CurrentArena(); Assert.That(ar1, Is.Not.EqualTo(ar2), "Failed to trigger a new arena"); // Check that both arenas are non-empty: Assert.That(subject.GetArenaOccupation(ar1).Value, Is.Not.Zero); Assert.That(subject.GetArenaOccupation(ar2).Value, Is.Not.Zero); // Run the scan (note we don't need all pointers, just one from each arena) var list = new Vector <long>(subject, mem); list.Push(x1); list.Push(x2); subject.ScanAndSweep(list); // Check nothing has been cleared Assert.That(subject.GetArenaOccupation(ar1).Value, Is.Not.Zero); Assert.That(subject.GetArenaOccupation(ar2).Value, Is.Not.Zero); }
public void deallocating_the_hash_map_releases_memory() { var mem = new MemorySimulator(Mega.Bytes(20)); var alloc = new Allocator(Mega.Bytes(10), Mega.Bytes(20), mem); var subject = new TaggedHashMap(256, alloc, mem); for (ulong i = 0; i < 128; i++) { subject.Add(i, i * 2); } // Check that memory is used... alloc.GetState(out var allocatedBytes, out var unallocatedBytes, out var occupiedArenas, out var emptyArenas, out var totalReferenceCount, out var largestContiguous); Assert.That(allocatedBytes, Is.GreaterThanOrEqualTo(6000), "Allocated bytes looks too small"); //Assert.That(unallocatedBytes, Is.LessThan(Mega.Bytes(10)), "Unallocated bytes looks too big: "+unallocatedBytes); Assert.That(occupiedArenas, Is.EqualTo(1), "Occupied arenas looks wrong"); Assert.That(emptyArenas, Is.GreaterThanOrEqualTo(100), "Empty arenas looks wrong"); Assert.That(totalReferenceCount, Is.GreaterThan(2), "Reference count looks wrong"); Assert.That(largestContiguous, Is.EqualTo(Allocator.ArenaSize), "Should not have exhausted memory!"); // Release the hash map subject.Deallocate(); // Check that everything is released alloc.GetState(out allocatedBytes, out unallocatedBytes, out occupiedArenas, out emptyArenas, out totalReferenceCount, out largestContiguous); Assert.That(allocatedBytes, Is.EqualTo(0), "Memory was not freed"); Assert.That(unallocatedBytes, Is.GreaterThan(Mega.Bytes(9)), "Unallocated bytes not correct"); Assert.That(occupiedArenas, Is.EqualTo(0), "Some arenas still occupied"); Assert.That(emptyArenas, Is.GreaterThanOrEqualTo(100), "Empty arenas looks wrong"); Assert.That(totalReferenceCount, Is.EqualTo(0), "Some references still dangling"); Assert.That(largestContiguous, Is.EqualTo(Allocator.ArenaSize), "Should not have exhausted memory!"); }
public void running_a_scan_when_no_pointers_are_referenced_resets_the_arena() { var bump = (Allocator.ArenaSize / 4) + 1; // three fit in each arena, with some spare var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(512, Mega.Bytes(1), mem); subject.Alloc(bump); var ar1 = subject.CurrentArena(); subject.Alloc(bump); subject.Alloc(bump); // fill up first arena var x2 = subject.Alloc(bump).Value; var ar2 = subject.CurrentArena(); Assert.That(ar1, Is.Not.EqualTo(ar2), "Failed to trigger a new arena"); // Check that both arenas are non-empty: Assert.That(subject.GetArenaOccupation(ar1).Value, Is.Not.Zero); Assert.That(subject.GetArenaOccupation(ar2).Value, Is.Not.Zero); // Run the scan (only including the second arena) var list = new Vector <long>(subject, mem); list.Push(x2); subject.ScanAndSweep(list); // Check nothing has been cleared Assert.That(subject.GetArenaOccupation(ar1).Value, Is.Zero, "Unreferenced arena was not reset"); Assert.That(subject.GetArenaOccupation(ar2).Value, Is.Not.Zero); }
public void can_create_a_vector_larger_than_the_arena_limit() { var memsize = Mega.Bytes(1); var mem = new MemorySimulator(memsize); var subject = new Vector <SampleElement>(new Allocator(0, memsize, mem), mem); uint full = (uint)(Allocator.ArenaSize / sizeof(long)) * 2; var expected = (full * 8) + ((full / 32) * 8); Console.WriteLine("Expecting to allocate " + expected); if (expected >= memsize) { Assert.Fail("memsize is not big enough for the test"); } for (int i = 0; i < full; i++) { subject.Push(Sample(i)); } var res = subject.Get(full - 1); Assert.That(res.Value.a, Is.EqualTo(full - 1)); }
public void trying_to_write_past_the_end_of_a_sibling_chain_will_fail() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Tree <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); //##### BUILD ##### subject.SetRootValue(Sample[0]); // First child of root var ptrRes = subject.AddChild(subject.Root, Sample[1]); if (!ptrRes.Success) { Assert.Fail("Failed to add child 1"); } // ( 1 ) // Second child of root ptrRes = subject.AddChild(subject.Root, Sample[2]); if (!ptrRes.Success) { Assert.Fail("Failed to add child 2"); } // ( 1, 2 ) //##### ACTION ##### // Try to write past the last index ptrRes = subject.InsertChild(parent: subject.Root, targetIndex: 3, element: Sample[3]); Assert.That(ptrRes.Success, Is.False, "Wrote pass the last valid index"); }
public void can_remove_values() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new TaggedHashMap(64, new Allocator(0, Mega.Bytes(1), mem), mem); subject.Add(50000000, 123); subject.Add(1, 456); var ok1 = subject.Get(1, out _); var ok2 = subject.Get(50000000, out _); var ok3 = subject.Get(50, out _); Assert.That(ok1, Is.True); Assert.That(ok2, Is.True); Assert.That(ok3, Is.False); // remove one value at beginning subject.Remove(1); ok1 = subject.Get(1, out _); ok2 = subject.Get(50000000, out _); ok3 = subject.Get(50, out _); Assert.That(ok1, Is.False); Assert.That(ok2, Is.True); Assert.That(ok3, Is.False); }
public void Vector__vs__LinkedList() { var sara_time = new Stopwatch(); var dotnet_time = new Stopwatch(); var mem = new MemorySimulator(Mega.Bytes(50)); var sara = new Vector <int>(new Allocator(0, Mega.Bytes(50), mem), mem); var dotnet = new LinkedList <int>(); sara_time.Start(); for (int i = 0; i < 2500; i++) { sara.Push(i); } for (int i = 0; i < 2500; i++) { sara.Pop(); } sara_time.Stop(); dotnet_time.Start(); for (int i = 0; i < 2500; i++) { dotnet.AddLast(i); } for (int i = 0; i < 2500; i++) { dotnet.RemoveLast(); } dotnet_time.Stop(); Assert.Pass("SArA: " + sara_time.Elapsed + " ; dotnet: " + dotnet_time.Elapsed); }
public void stress_test() { var rnd = new Random(); // we deliberately use a small initial size to stress the scaling. // if you can afford to oversize the map, that will make things a lot faster var mem = new MemorySimulator(Mega.Bytes(10)); var subject = new TaggedHashMap(100, new Allocator(0, Mega.Bytes(10), mem), mem); subject.Add(0, 1); for (int i = 0; i < /*100000*/ 25_000; i++) // 25'000 should be under a second { if (!subject.Put((ulong)rnd.Next(1, 1_000_000), (ulong)i, true)) { Assert.Fail("Put rejected the change"); } subject.Remove((ulong)rnd.Next(1, 1_000_000)); } Assert.That(subject.Count, Is.GreaterThan(1000)); // there will probably be key collisions var ok = subject.Get(0, out var val); Assert.That(ok, Is.True); Assert.That(val, Is.EqualTo(1)); }
public void building_and_walking_a_tree() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Tree <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); //##### BUILD ##### subject.SetRootValue(Sample[0]); // First child of root var ptrRes = subject.AddChild(subject.Root, Sample[1]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } // Second child of root ptrRes = subject.AddChild(subject.Root, Sample[2]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } var rc2 = ptrRes.Value; // Child of second child ptrRes = subject.AddChild(rc2, Sample[3]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } //##### WALK ##### var body1 = subject.ReadBody(subject.Root); Assert.That(body1, Is.EqualTo(Sample[0])); var child1Res = subject.Child(subject.Root); Assert.IsTrue(child1Res.Success); var child1childRes = subject.Child(child1Res.Value); Assert.IsFalse(child1childRes.Success); var child2Res = subject.Sibling(child1Res.Value); Assert.IsTrue(child2Res.Success); var child3Res = subject.Sibling(child2Res.Value); Assert.IsFalse(child3Res.Success); var child2childRes = subject.Child(child2Res.Value); Assert.IsTrue(child2childRes.Success); var body_c2c1 = subject.ReadBody(child2childRes.Value); Assert.That(body_c2c1, Is.EqualTo(Sample[3])); }
public void can_allocate_memory_from_a_pool_and_get_a_pointer() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(100, Mega.Bytes(10), mem); long ptr = subject.Alloc(byteCount: Kilo.Bytes(1)).Value; Assert.That(ptr, Is.GreaterThanOrEqualTo(100)); }
[Test] // The vector class can be used to store larger chunks of data public void requesting_a_block_larger_than_a_single_area_fails() { // Doing this to keep things very simple var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(512, Mega.Bytes(1), mem); var result = subject.Alloc(Allocator.ArenaSize * 2); Assert.That(result.Success, Is.False); }
public void a_second_allocation_returns_different_memory() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(100, Mega.Bytes(10), mem); long ptr1 = subject.Alloc(byteCount: 256).Value; long ptr2 = subject.Alloc(byteCount: 256).Value; Assert.That(ptr1, Is.Not.EqualTo(ptr2)); }
public void can_check_for_presence_of_a_key() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new TaggedHashMap(64, new Allocator(0, Mega.Bytes(1), mem), mem); subject.Add(123, 0); subject.Add(1, 456); Assert.That(subject.ContainsKey(123), Is.True); Assert.That(subject.ContainsKey(321), Is.False); }
public void can_remove_last_child_by_an_index() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Tree <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); //##### BUILD ##### subject.SetRootValue(Sample[0]); // First child of root var ptrRes = subject.AddChild(subject.Root, Sample[1]); if (!ptrRes.Success) { Assert.Fail("Failed to add child 1"); } // ( 1 ) // Second child of root ptrRes = subject.AddChild(subject.Root, Sample[2]); if (!ptrRes.Success) { Assert.Fail("Failed to add child 2"); } // ( 1, 2 ) // Third child of root ptrRes = subject.AddChild(subject.Root, Sample[3]); if (!ptrRes.Success) { Assert.Fail("Failed to add child 3"); } // ( 1, 2, 3 ) //##### ACTION ##### // Delete first item subject.RemoveChild(parent: subject.Root, targetIndex: 2); // ( 1, 2 ) //##### WALK ##### var wres1 = subject.Child(subject.Root); var wres2 = subject.SiblingR(wres1); Assert.That(wres2.Success, Is.True, "Failed to get full chain"); Assert.That(subject.SiblingR(wres2).Success, Is.False, "Resulting chain was too long"); var newChild1 = subject.ReadBody(wres1.Value); Assert.That(newChild1, Is.EqualTo(Sample[1]), "Incorrect data (1)"); var newChild2 = subject.ReadBody(wres2.Value); Assert.That(newChild2, Is.EqualTo(Sample[2]), "Incorrect data (2)"); }
public void put_can_replace_an_existing_value() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new TaggedHashMap(64, new Allocator(0, Mega.Bytes(1), mem), mem); subject.Put(1, 1, true); subject.Put(1, 2, true); // overwrite subject.Put(1, 3, false); // silently abort subject.Get(1, out var result); Assert.That(result, Is.EqualTo(2)); }
public void allocating_enough_memory_changes_arena() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(100, Mega.Bytes(1), mem); int first = subject.CurrentArena(); long ptr1 = subject.Alloc(Allocator.ArenaSize).Value; long ptr2 = subject.Alloc(Kilo.Bytes(1)).Value; int second = subject.CurrentArena(); Assert.That(ptr1, Is.Not.EqualTo(ptr2)); Assert.That(first, Is.Not.EqualTo(second)); }
public void deallocating_an_old_allocation_does_nothing() { // Older items just hang around until the entire arena is abandoned var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(100, Mega.Bytes(10), mem); long ptr1 = subject.Alloc(byteCount: 256).Value; long ptr2 = subject.Alloc(byteCount: 256).Value; subject.Deref(ptr1); long ptr3 = subject.Alloc(byteCount: 512).Value; Assert.That(ptr3, Is.GreaterThan(ptr2)); }
public void can_directly_deallocate_a_pointer() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(100, Mega.Bytes(10), mem); long ptr = subject.Alloc(byteCount: 256).Value; subject.Deref(ptr); var ar = subject.CurrentArena(); var refs = subject.ArenaRefCount(ar); Assert.That(refs.Value, Is.Zero); }
public void memory_exhaustion_results_in_an_error_code() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(10, Mega.Bytes(1), mem); Result <long> result = default; for (int i = 0; i < 17; i++) { result = subject.Alloc(Allocator.ArenaSize - 1); } Assert.That(result.Success, Is.False); }
public void Vector__vs__List() { var sara_time = new Stopwatch(); var dotnet_time = new Stopwatch(); var mem = new MemorySimulator(Mega.Bytes(50)); var sara = new Vector <int>(new Allocator(0, Mega.Bytes(50), mem), mem); var dotnet = new List <int>(); sara_time.Start(); int saraSum = 0; for (int i = 0; i < 2500; i++) { saraSum += i; sara.Push(i); } for (int i = 0; i < 2500; i++) { saraSum -= sara.Get((uint)i).Value; } for (int i = 0; i < 2500; i++) { sara.Pop(); } sara_time.Stop(); dotnet_time.Start(); int dotnetSum = 0; for (int i = 0; i < 2500; i++) { dotnetSum += i; dotnet.Add(i); } for (int i = 0; i < 2500; i++) { dotnetSum -= dotnet[i]; } for (int i = 0; i < 2500; i++) { dotnet.RemoveAt(dotnet.Count - 1); } dotnet_time.Stop(); Assert.Pass("SArA: " + sara_time.Elapsed + " result = " + saraSum + "; dotnet: " + dotnet_time.Elapsed + " result = " + dotnetSum); }
public void popping_the_last_item_from_a_list_gives_its_value() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Vector <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); Assert.That(subject.Length(), Is.Zero); subject.Push(Sample1()); subject.Push(Sample2()); Assert.That(subject.Length(), Is.EqualTo(2)); Assert.That(subject.Pop().Value, Is.EqualTo(Sample2())); Assert.That(subject.Pop().Value, Is.EqualTo(Sample1())); Assert.That(subject.Length(), Is.Zero); }
public void can_continue_a_sibling_chain_without_going_to_parent() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Tree <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); //##### BUILD ##### subject.SetRootValue(Sample[0]); // First child of root var ptrRes = subject.AddChild(subject.Root, Sample[1]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } // Second child of root ptrRes = subject.AddChild(subject.Root, Sample[2]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } var rc2 = ptrRes.Value; // Child of second child ptrRes = subject.AddChild(rc2, Sample[3]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } //##### ACTION ##### // add a third child to root by second child ptrRes = subject.AddSibling(rc2, Sample[4]); if (!ptrRes.Success) { Assert.Fail("Failed to add sibling"); } //##### WALK ##### var wres = subject.Child(subject.Root); wres = subject.SiblingR(wres); wres = subject.SiblingR(wres); Assert.That(wres.Success, Is.True, "Failed to get full chain"); var final = subject.ReadBody(wres.Value); Assert.That(final, Is.EqualTo(Sample[4]), "Incorrect data"); }
public void TaggedHashMap__vs__Dictionary() { var rnd = new Random(); var sara_time = new Stopwatch(); var dotnet_time = new Stopwatch(); var mem = new MemorySimulator(Mega.Bytes(50)); var sara = new TaggedHashMap(0, new Allocator(0, Mega.Bytes(50), mem), mem); var dotnet = new Dictionary <ulong, ulong>(0); sara_time.Start(); for (ulong i = 0; i < 2500; i++) { var insKey = (ulong)rnd.Next(1, 1000000); var remKey = (ulong)rnd.Next(1, 1000000); if (!sara.Put(insKey, i, true)) { Assert.Fail("Put rejected the change at " + i); } sara.Remove(remKey); } sara_time.Stop(); dotnet_time.Start(); for (ulong i = 0; i < 2500; i++) { var insKey = (ulong)rnd.Next(1, 1000000); var remKey = (ulong)rnd.Next(1, 1000000); if (dotnet.ContainsKey(insKey)) { dotnet[insKey] = i; } else { dotnet.Add(insKey, i); } dotnet.Remove(remKey); } dotnet_time.Stop(); Assert.Pass("SArA: " + sara_time.Elapsed + "; dotnet: " + dotnet_time.Elapsed); }
public void can_store_and_read_array_elements() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Vector <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); Assert.That(subject.Length(), Is.Zero); subject.Push(Sample1()); subject.Push(Sample2()); Assert.That(subject.Length(), Is.EqualTo(2)); var r = subject.Get(0).Value; Assert.That(r, Is.EqualTo(Sample1())); Assert.That(subject.Get(1).Value, Is.EqualTo(Sample2())); }
public void can_overwrite_entries_by_explicit_index() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Vector <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); Assert.That(subject.Length(), Is.Zero); subject.Push(Sample1()); subject.Push(Sample2()); Assert.That(subject.Length(), Is.EqualTo(2)); subject.Set(0, Sample3()); Assert.That(subject.Get(0).Value, Is.EqualTo(Sample3())); Assert.That(subject.Get(1).Value, Is.EqualTo(Sample2())); }
public void elements_per_chunk_is_reasonable() { Console.WriteLine(Allocator.ArenaSize); var mem_a = new MemorySimulator(Kilo.Bytes(80)); var mem_b = new MemorySimulator(Kilo.Bytes(80)); var mem_c = new MemorySimulator(Kilo.Bytes(80)); var structVector = new Vector <SampleElement>(new Allocator(0, Kilo.Bytes(80), mem_a), mem_a); var bigStructVector = new Vector <HugeStruct> (new Allocator(0, Kilo.Bytes(80), mem_b), mem_b); var byteVector = new Vector <byte> (new Allocator(0, Kilo.Bytes(80), mem_c), mem_c); Assert.That(byteVector.ElemsPerChunk, Is.LessThan(70)); // Not too big on small elements Assert.That(structVector.ElemsPerChunk, Is.GreaterThan(30)); Assert.That(bigStructVector.ElemsPerChunk, Is.LessThan(32)); // scales down to fit arenas }
public void after_deleting_root_node_all_memory_should_be_released() { var mem = new MemorySimulator(Mega.Bytes(1)); var alloc = new Allocator(0, Mega.Bytes(1), mem); alloc.GetState(out var bytes, out _, out _, out _, out _, out _); Assert.That(bytes, Is.Zero, "Allocator did not start empty"); //##### BUILD ##### var subject = new Tree <SampleElement>(alloc, mem); subject.SetRootValue(Sample[0]); // First child of root var ptrRes = subject.AddChild(subject.Root, Sample[1]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } // Second child of root ptrRes = subject.AddChild(subject.Root, Sample[2]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } var rc2 = ptrRes.Value; // Child of second child ptrRes = subject.AddChild(rc2, Sample[3]); if (!ptrRes.Success) { Assert.Fail("Failed to add child"); } alloc.GetState(out bytes, out _, out _, out _, out _, out _); Assert.That(bytes, Is.Not.Zero, "No memory was allocated"); //##### Destroy ##### subject.Deallocate(); alloc.GetState(out bytes, out _, out _, out _, out _, out _); Assert.That(bytes, Is.Zero, "Not all memory was released"); }
public void can_add_elements_after_removing_them() { var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Vector <SampleElement>(new Allocator(0, Mega.Bytes(1), mem), mem); Assert.That(subject.Length(), Is.Zero); subject.Push(Sample1()); subject.Push(Sample2()); Assert.That(subject.Length(), Is.EqualTo(2)); subject.Pop(); subject.Push(Sample3()); Assert.That(subject.Get(1).Value, Is.EqualTo(Sample3()), "Get 1 is wrong"); Assert.That(subject.Get(0).Value, Is.EqualTo(Sample1()), "Get 0 is wrong"); }
public void can_add_and_remove_current_referenced_pointers() { // This increments and decrements ref counts? // Free is the equivalent of directly setting ref count to zero? Or is it just a synonym for Deref? // We can keep an overall refcount for the arena and ignore the individual references (except for the head, as an optimisation) // We don't protect from double-free var mem = new MemorySimulator(Mega.Bytes(1)); var subject = new Allocator(100, Mega.Bytes(1), mem); long ptr = subject.Alloc(byteCount: 256).Value; subject.Reference(ptr); subject.Reference(ptr); subject.Deref(ptr); Assert.Pass(); }