From f902ddb1357093093d69dea9f75c2e42ae23d621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?JasonXuDeveloper=20-=20=E5=82=91?= Date: Sat, 27 May 2023 15:40:32 +1000 Subject: [PATCH] v0.8.0f6 - fix crash on android 32bit - fix block calling LoadScene --- README.md | 4 +- README_zh_cn.md | 2 +- .../JEngine/Core/Manager/AssetMgr.cs | 6 +- .../JEngine/Core/Manager/LifeCycleMgr.cs | 78 ++++++++- .../JEngine/Core/Util/UnmanagedMemoryPool.cs | 154 ------------------ .../Core/Util/UnmanagedMemoryPool.cs.meta | 3 - package.json | 2 +- 7 files changed, 77 insertions(+), 172 deletions(-) delete mode 100644 UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs delete mode 100644 UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs.meta diff --git a/README.md b/README.md index 9fbe2159..5d612eda 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ badge - + [README_zh_cn.md](README_zh_cn.md)

Documentation » @@ -31,7 +31,7 @@ -# JENGINE v0.8.0f5 +# JENGINE v0.8.0f6 **JEngine is an out-of-the-box framework designed for Unity developers. It encapsulates powerful functions. Beginners can also get started quickly and easily create games that can be updated in runtime.** diff --git a/README_zh_cn.md b/README_zh_cn.md index 635d84f6..2e1c2a6c 100644 --- a/README_zh_cn.md +++ b/README_zh_cn.md @@ -30,7 +30,7 @@ -# JENGINE v0.8.0f5 +# JENGINE v0.8.0f6 JEngine是针对Unity开发者设计的**开箱即用**的框架,封装了强大的功能,小白也能**快速上手**,**轻松制作**可以**热更新的游戏** diff --git a/UnityProject/Assets/Dependencies/JEngine/Core/Manager/AssetMgr.cs b/UnityProject/Assets/Dependencies/JEngine/Core/Manager/AssetMgr.cs index cbd5d838..e715283d 100644 --- a/UnityProject/Assets/Dependencies/JEngine/Core/Manager/AssetMgr.cs +++ b/UnityProject/Assets/Dependencies/JEngine/Core/Manager/AssetMgr.cs @@ -357,8 +357,10 @@ public static void LoadScene(string path, bool additive = false, string package { SceneOperationHandle handle = GetPackage(package) .LoadSceneAsync(path, additive ? LoadSceneMode.Additive : LoadSceneMode.Single); - handle.Task.Wait(); - RemoveUnusedAssets(); + handle.Task.ContinueWith((_, __) => RemoveUnusedAssets() + , null); + _ = handle.Task; + Log.PrintWarning("LoadScene will not wait for scene loading complete. Use LoadSceneAsync instead."); } public static async Task LoadSceneAsync(string path, bool additive = false, string package = null) diff --git a/UnityProject/Assets/Dependencies/JEngine/Core/Manager/LifeCycleMgr.cs b/UnityProject/Assets/Dependencies/JEngine/Core/Manager/LifeCycleMgr.cs index 5f253eb3..5d8fb7e3 100644 --- a/UnityProject/Assets/Dependencies/JEngine/Core/Manager/LifeCycleMgr.cs +++ b/UnityProject/Assets/Dependencies/JEngine/Core/Manager/LifeCycleMgr.cs @@ -26,6 +26,8 @@ using System; using UnityEngine; +using System.Threading; +using Unity.Collections; using System.Reflection; using System.Collections.Generic; using Unity.Collections.LowLevel.Unsafe; @@ -53,7 +55,24 @@ private struct LifeCycleItem public static LifeCycleItem* Create(in void* instancePtr, in ulong gcAddr, Action action, Func cond) { - LifeCycleItem* item = (LifeCycleItem*)Pool.Allocate(sizeof(LifeCycleItem)); + byte* ptr = UsageList; + LifeCycleItem* item = ItemList; + byte* max = ptr + MaxSize; + while (ptr < max) + { + if (*ptr == 0) + { + *ptr = 1; + break; + } + + ptr++; + item++; + } + + if (ptr == max) + throw new Exception("LifeCycleMgr: LifeCycleItem is full!"); + item->InstancePtr = (IntPtr)instancePtr; item->_instanceGCHandleAddress = gcAddr; item->_actionPtr = UnsafeUtility.PinGCObjectAndGetAddress(action, out item->_actionGCHandleAddress); @@ -72,7 +91,7 @@ public void Dispose() UnsafeUtility.ReleaseGCObject(_condGCHandleAddress); fixed (LifeCycleItem* ptr = &this) { - Pool.Free((byte*)ptr); + UsageList[ptr - ItemList] = 0; } } } @@ -100,12 +119,27 @@ public static void Initialize() /// 单例 /// public static LifeCycleMgr Instance => _instance; - + + /// + /// 非托管内存 + /// + private static readonly LifeCycleItem* ItemList = + (LifeCycleItem*)UnsafeUtility.Malloc(sizeof(LifeCycleItem) * MaxSize, 4, Allocator.Persistent); + + /// + /// 使用列表 + /// + private static readonly byte* UsageList = (byte*)UnsafeUtility.Malloc(MaxSize, 4, Allocator.Persistent); + + /// + /// 最大数量 + /// + private const int MaxSize = 10000; + /// - /// 非托管内存池 - /// 最多同时10240个被占用的任务(480KB内存) + /// 锁 /// - private static readonly UnmanagedMemoryPool Pool = new UnmanagedMemoryPool(sizeof(LifeCycleItem) * 10240); + private static SpinLock _createLock; /// /// unity周期 @@ -120,6 +154,19 @@ private void Awake() _ignoreWithoutInInstancesFunc = IgnoreWithoutInInstances; _ignoreWithInInstancesFunc = IgnoreWithInInstances; + GC.AddMemoryPressure(sizeof(LifeCycleItem) * MaxSize); + GC.AddMemoryPressure(MaxSize); + } + + /// + /// 清理非托管 + /// + private void OnDestroy() + { + UnsafeUtility.Free(ItemList, Allocator.Persistent); + UnsafeUtility.Free(UsageList, Allocator.Persistent); + GC.RemoveMemoryPressure(sizeof(LifeCycleItem) * MaxSize); + GC.RemoveMemoryPressure(MaxSize); } /// @@ -175,7 +222,20 @@ private void Awake() /// /// private static IntPtr GetLifeCycleItem(in void* addr, in ulong gcAddr, Action action, - Func cond) => (IntPtr)LifeCycleItem.Create(in addr, in gcAddr, action, cond); + Func cond) + { + bool gotLock = false; + try + { + _createLock.Enter(ref gotLock); + return + (IntPtr)LifeCycleItem.Create(in addr, in gcAddr, action, cond); + } + finally + { + if (gotLock) _createLock.Exit(); + } + } /// /// Add awake task @@ -576,12 +636,12 @@ private bool IgnoreWithInInstances(in LifeCycleItem* item) /// remove obj from instances /// private Predicate RemoveInstanceIfContainsPredicate => RemoveInstanceIfContains; - + /// /// execute once task /// private bool _onceTaskExecuting; - + /// /// 处理只调用一次的任务 /// diff --git a/UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs b/UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs deleted file mode 100644 index eecd2916..00000000 --- a/UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs +++ /dev/null @@ -1,154 +0,0 @@ -// -// UnmanagedMemoryPool.cs -// -// Author: -// JasonXuDeveloper(傑) -// -// Copyright (c) 2020 JEngine -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; - -namespace JEngine.Core -{ - /// - /// Memory pool that returns unmanaged memory - /// - public unsafe class UnmanagedMemoryPool - { - /// - /// Allocated unmanaged memory - /// Structure: - /// Chain: - /// 1 byte of whether or not hold in use -> 8 bytes of length of n -> n - /// ---- ---- ---- ---- ---- ---- - /// | 1 | 8 | n1 | 1 | 8 | n2 | ...... - /// ---- ---- ---- ---- ---- ---- - /// - private readonly byte* _memory; - - /// - /// Allocated size - /// - private readonly long _memoryLength; - - /// - /// Create a memory pool - /// - /// - public UnmanagedMemoryPool(long size = 1024) - { - _memory = (byte*)UnsafeUtility.Malloc(size, 1, Allocator.Persistent); - //ensure 0 - UnsafeUtility.MemClear(_memory, size); - *_memory = 0; - _memoryLength = size; - GC.AddMemoryPressure(size); - } - - /// - /// Destroy the memory pool - /// - ~UnmanagedMemoryPool() - { - Destroy(); - } - - /// - /// Destroy the current memory pool - /// - public void Destroy() - { - UnsafeUtility.Free(_memory, Allocator.Persistent); - GC.RemoveMemoryPressure(_memoryLength); - } - - /// - /// Allocate memory - /// - /// - /// - /// - public byte* Allocate(long size) - { - //look for valid blocks - byte* ptr = _memory; - while (true) - { - //ensure it is not out of boundary - if (ptr - _memory > _memoryLength || ptr + 9 - _memory > _memoryLength) - { - //no enough allocated memory - throw new OutOfMemoryException("memory pool out of memory"); - } - - if (*ptr == 0) - { - //if the block is not in use, check if the size is enough - long len = *(long*)(ptr + 1); - byte* next = ptr + 9 + len; - //ensure won't cross the boundary - if (next > _memory + _memoryLength) - { - //no enough allocated memory - throw new OutOfMemoryException("memory pool out of memory"); - } - //ensure not intersecting with the next block - if (*next == 0) - { - if (len == 0 || len >= size)//0 -> uninitialized - { - //if the size is enough, mark the block as in use - *ptr = 1; - //mark size - *(long*)(ptr + 1) = size; - return ptr + 9; - } - } - } - - //if the block is in use, or the size is not enough, move to the next block - ptr += *(long*)(ptr + 1) + 9; - } - } - - /// - /// Free allocated memory - /// - /// - /// - public void Free(byte* ptr) - { - //ensure p is inside of the memory pool - if (ptr < _memory || ptr >= _memory + _memoryLength) - { - throw new ArgumentException("ptr is not inside of the memory pool"); - } - //get length of p - long len = *(long*)(ptr - 8); - //clear - UnsafeUtility.MemClear(ptr, len); - //mark the block as not in use - *(ptr - 9) = 0; - } - } -} \ No newline at end of file diff --git a/UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs.meta b/UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs.meta deleted file mode 100644 index 2984b230..00000000 --- a/UnityProject/Assets/Dependencies/JEngine/Core/Util/UnmanagedMemoryPool.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: aeb2d35ff5794f7994756b4bf567c280 -timeCreated: 1673827624 \ No newline at end of file diff --git a/package.json b/package.json index c81745f4..f3c7cf2c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.jasonxudeveloper.jengine", - "version": "0.8.0f5", + "version": "0.8.0f6", "displayName": "JEngine", "description": "The solution that allows unity games update in runtime.", "license": "MIT",