// // Copyright (c) .NET Foundation and Contributors // Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. // using nanoFramework.TestFramework; using System; namespace NFUnitTestSystemLib { [TestClass] public class UnitTestGCTest { internal class FinalizeObject { public static FinalizeObject m_currentInstance = null; ~FinalizeObject() { if (!m_hasFinalized1) { // First finalization // Put this object back into a root by creating // a reference to it. FinalizeObject.m_currentInstance = this; // Indicate that this instance has finalized once. m_hasFinalized1 = true; // Place a reference to this object back in the // finalization queue. GC.ReRegisterForFinalize(this); } else { // Second finalization m_hasFinalized2 = true; } } } static bool m_hasFinalized1 = false; static bool m_hasFinalized2 = false; static bool m_Test1Result = false; [TestMethod] public void SystemGC1_Test() { /// /// 1. Create a FinalizeObject. /// 2. Release the reference /// 3. Allow for GC /// 4. Run ReRegisterForFinalize /// 5. Allow for GC /// 6. Verify that object has been collected /// /// // Tests ReRegisterForFinalize // Create a FinalizeObject. FinalizeObject mfo = new FinalizeObject(); m_hasFinalized1 = false; m_hasFinalized2 = false; // Release reference mfo = null; // Allow GC GC.WaitForPendingFinalizers(); int sleepTime = 1000; int slept = 0; while (!m_hasFinalized1 && slept < sleepTime) { // force GC run caused by memory allocation var dummyArray = new byte[1024 * 1024 * 1]; System.Threading.Thread.Sleep(10); slept += 10; } OutputHelper.WriteLine($"GC took {slept}"); // At this point mfo will have gone through the first Finalize. // There should now be a reference to mfo in the static // FinalizeObject.m_currentInstance field. Setting this value // to null and forcing another garbage collection will now // cause the object to Finalize permanently. // Reregister and allow for GC FinalizeObject.m_currentInstance = null; GC.WaitForPendingFinalizers(); sleepTime = 1000; slept = 0; while (!m_hasFinalized2 && slept < sleepTime) { // force GC run caused by memory allocation var dummyArray = new byte[1024 * 1024 * 1]; System.Threading.Thread.Sleep(10); slept += 10; } OutputHelper.WriteLine($"GC took {slept}"); m_Test1Result = m_hasFinalized2; Assert.IsTrue(m_hasFinalized2); } [TestMethod] public void SystemGC2_Test() { /// /// 1. Create a FinalizeObject. /// 2. Release the reference /// 3. SupressFinalize /// 3. Allow for GC /// 6. Verify that object has not been collected /// /// // Tests SuppressFinalize // Create a FinalizeObject. FinalizeObject mfo = new FinalizeObject(); m_hasFinalized1 = false; m_hasFinalized2 = false; // Releasing GC.SuppressFinalize(mfo); mfo = null; // Allow GC GC.WaitForPendingFinalizers(); int sleepTime = 1000; int slept = 0; while (!m_hasFinalized1 && slept < sleepTime) { // force GC run caused by memory allocation var dummyArray = new byte[1024 * 1024 * 1]; System.Threading.Thread.Sleep(10); slept += 10; } OutputHelper.WriteLine($"GC took {slept}"); Assert.IsFalse(m_hasFinalized1); } [TestMethod] public void SystemGC3_Test() { /// /// 1. Create a FinalizeObject. /// 2. Release the reference /// 3. SupressFinalize /// 3. Allow for GC /// 6. Verify that object has not been collected /// /// // Tests WaitForPendingFinalizers, dependant on test 1 // will auto-fail if test 1 fails. OutputHelper.Write("Tests WaitForPendingFinalizers, dependant on test 1"); OutputHelper.WriteLine("will auto-fail if test 1 fails."); Assert.IsTrue(m_Test1Result); // Create a FinalizeObject. FinalizeObject mfo = new FinalizeObject(); m_hasFinalized1 = false; m_hasFinalized2 = false; // Releasing mfo = null; int sleepTime = 1000; int slept = 0; while (!m_hasFinalized1 && slept < sleepTime) { // force GC run caused by memory allocation var dummyArray = new byte[1024 * 1024 * 1]; System.Threading.Thread.Sleep(10); slept += 10; } OutputHelper.WriteLine($"GC took {slept}"); // Wait for GC GC.WaitForPendingFinalizers(); // Releasing again FinalizeObject.m_currentInstance = null; sleepTime = 1000; slept = 0; while (!m_hasFinalized2 && slept < sleepTime) { // force GC run caused by memory allocation var dummyArray = new byte[1024 * 1024 * 1]; System.Threading.Thread.Sleep(10); slept += 10; } OutputHelper.WriteLine($"GC took {slept}"); // Wait for GC GC.WaitForPendingFinalizers(); Assert.IsTrue(m_hasFinalized2); } } }