Memory Considerations when targeting WebGLhtml
構建WebGL目標時的內存考量web
Memory in Unity WebGL can be a constraining factor restricting the complexity of the content you can run, so we would like to provide some explanation on how memory is used in WebGL.數據庫
對於Unity WebGL來講,內存限制了所運行內容的複雜度。下面咱們將解釋一下在WebGL中內存是如何被使用的。瀏覽器
Your WebGL content will run inside a browser, so any memory has to be allocated by the browser within the browser’s memory space. The amount of available memory can vary a lot depending on the browser, OS and device used. Determining factors include whether the browser is a 32 or 64 bit process, whether the browser uses separate processes for each tab or has your content share a memory space with all other open tabs, and how much memory the browser’s JavaScript engine requires to parse your code.數據結構
由於WebGL內容是運行於瀏覽器當中的,因此其所需內存都是從瀏覽器內存空間裏分配的。根據所用瀏覽器、操做系統和設備的不一樣,WebGL內容可用的內存可能會差異很大。決定因素包括:瀏覽器是32位的仍是64位的,瀏覽器爲每一個標籤頁使用獨立的進程仍是讓WebGL內容和其它標籤頁使用共享的內存,以及瀏覽器JavaScript引擎解析WebGL內容代碼須要多少內存。app
There are multiple areas where Unity WebGL content will require the browser to allocate significant amounts of memory:less
在如下幾個方面,Unity WebGL內容要求瀏覽器分配大量內存:ide
Unity Heapoop
Unity堆內存優化
This is the memory Unity uses to store all it’s state, managed and native objects and currently loaded assets and scenes. This is similar to the memory used by Unity players on any other platform. You can configure the size of this in the Unity WebGL player settings (But for faster iteration, you can also edit the TOTAL_MEMORY value written to the generated html file). You can use the Unity Profiler to profile and sample the contents of this memory. This memory will be created as a TypedArray of bytes in JavaScript code, and requires the browser be able to allocate a consecutive block of memory of this size. You will want this space to be as small as possible (so that the browser will be able to allocate it even if memory is fragmented), but large enough to fit all the data required to play any scene of your content.
對於這些內存,Unity用於存儲其全部狀態、託管的原生對象和當前加載的資源場景。這相似於Unity播放器在其餘任何平臺上所使用的內存。能夠在Unity WebGL播放器設置中配置該內存的大小(爲了快速迭代,也能夠編輯已寫入生成的html文件的TOTAL_MEMORY值)。您也可使用Unity Profiler對該內存的內容進行抽樣和調試。該內存以JavaScript代碼的TypedArray字節形式被建立,並要求瀏覽器可以按其大小分配連續的內存塊。咱們但願該空間儘量小(這樣當內存零碎時瀏覽器仍然可以分配該空間),但仍足以容納播聽任何內容場景時所需的數據。
Asset Data
資源數據
When you create a Unity WebGL build, Unity will write out a .data file containing all the scenes and assets needed for your content. Since WebGL does not have a real file system, this file will be downloaded before your content can start, and the uncompressed data will be kept in a consecutive block of browser memory for the whole time your content is run. So, to keep both download times and memory usage low, you should try to keep this data as small as possible. See the documentation page on Reducing File size for information on how to optimize the build size of your assets.
當您建立Unity WebGL構建時,Unity將會輸出一個.data文件,其包含WebGL內容所需的全部場景和資源。因爲WebGL沒有真實的文件系統,因此在開始運行內容以前,.data文件須要先被加載,同時,在內容運行的全部時間裏,這些未壓縮的文件將一直被保存在連續的瀏覽器內存塊裏。爲了下降下載時間和內存佔用,您應該讓這些數據儘量小。請參見文檔下降文件大小,得到優化資源構建大小的相關信息。
Another thing you can do to reduce load times and the amount of memory used for assets is to pack your asset data into AssetBundles. By doing so, you get full control of when your assets need to be downloaded, and you can unload them when you no longer need them, which will free any memory used by them. Note that AssetBundles will be loaded directly into the Unity heap and will not result in additional allocations by the browser (unless you use Asset Bundle Caching using WWW.LoadFromCacheOrDownload, which is using a memory-mapped Virtual File System, backed by the browser’s IndexedDB).
有另一個方法能夠下降資源的加載時間和內存佔用,其是將資源數據打包進AssetBundles。這樣作,您便能徹底控制何時加載資源,以及在不須要的時候卸載它們以釋放它們所佔用的內存。請注意,AssetBundles會被直接加載到Unity堆內存中,而不會形成瀏覽器的額外內存分配(除非您經過WWW.LoadFromCacheOrDownload使用Asset Bundle Caching技術,該技術採用了基於瀏覽器索引數據庫的內存映射虛擬文件系統)。
Memory needed to parse the code
解析代碼所需的內存
Another issue related to memory is the memory required by the browser’s JavaScript engine. Unity will emit very large files of millions of lines of generated JavaScript code, which is an order of magnitude larger than common uses of JavaScript code in browsers. Some JavaScript engines may allocate some rather large data structures to parse and optimize this code, which may results in memory spikes of up to several Gigabytes of memory when loading the content in some cases. We expect that future technologies like WebAssembly will eventually eliminate this problem, but until then, the best advise we can give is to do what you can to keep the size of the emitted code low. See the comments on distribution size here for more information on how to do that.
跟內存相關的另外一個問題是瀏覽器JavaScript引擎所需的內存。Unity會生成包含數以百萬行JavaScript代碼的很是大的文件,其數量級比瀏覽器裏一般運行的代碼量可要大得多。一些JavaScript引擎會分配至關大的數據結構以解析和優化這些代碼,某些狀況下可能致使加載內容時內存峯值上升到幾千兆字節。咱們但願將來諸如WebAssembly之類的技術能最終解決這個問題。但在那以前,咱們能給的最好建議是盡您所能以下降發行的代碼量。請點擊這裏以查看跟發佈大小相關的評論,得到解決問題的更多信息。
Dealing with memory issues
應對內存問題
When you see an error related to memory in a Unity WebGL build, it is important to understand whether it is the browser which is failing to allocate memory or if the Unity WebGL runtime is failing to allocate a free block of memory within the pre-allocated block of the Unity heap. If the browser is failing to allocate memory, then it may help to try to reduce the size used by one or more of the memory areas above (for instance by reducing the size of the Unity heap). On the other hand, if the Unity runtime is failing to allocate a block inside the Unity heap, you may want to increase the size of that instead.
當您在Unity WebGL構建當中看到內存相關的錯誤,區分如下兩點很重要,是瀏覽器沒法分配內存,仍是Unity WebGL運行時沒法在預先分配好的Unity堆內存塊中分配空閒內存。若是是瀏覽器沒法分配內存,那麼嘗試下降以上內存區域所使用的大小可能會有幫助(好比下降Unity堆內存的大小)。另外一方面,若是是Unity運行時沒法在Unity WebGL堆內存中分配內存塊,則能夠相應增長堆內存的大小。
Unity will try to interpret error messages to tell which of the two it is (and provide suggestions on what to do). Since different browsers may report different messages, that is not always easy, however, and we may not be interpreting all of them. When you see a generic 「Out of memory」 error from the browser, it is likely to be an issue of the browser running out of memory (where you might want to use a smaller Unity heap). Also, you may sometimes see browsers simply crashing when loading Unity content without showing a human-parseable error message. This can have many reasons, but is frequently caused by JavaScript engines requiring too much memory to parse and optimize the generated code.
Unity會嘗試分析瀏覽器錯誤信息以告訴您是以上兩個錯誤當中的哪一個(並給出怎麼應對的建議)。由於不一樣瀏覽器可能會報不一樣的錯誤信息,因此有時分析很困難,沒法徹底分析。當您看到瀏覽器產生「內存不足」之類的錯誤時,多是瀏覽器內存用光形成的問題(這時您可能想使用小一些的Unity堆內存)。此外,您有時會碰到加載Unity內容時瀏覽器直接崩潰,而沒有顯示可閱讀的錯誤信息。有不少可能緣由,但一般是由於JavaScript引擎須要過多的內存以分析和優化產生的代碼所致使的。
Garbage Collection considerations
垃圾回收機制考量
When you allocate managed objects in Unity, they will need to be garbage collected when they are no longer used. See our documentation on automatic memory management for more information. In WebGL, this is the same. Managed, garbage collected memory is allocated inside the Unity heap.
對於Unity中的託管對象,當它們再也不被使用時,須要作垃圾回收處理。請查看文檔自動內存管理,獲取更多信息。在WebGL中,也有一樣的機制。託管的垃圾回收內存分配於Unity堆內存中。
One distinction in WebGL, however, concerns the points in time when garbage collection (GC) can take place. To perform garbage collection, the GC would normally need to pause all running threads and inspect their stacks and registers for loaded object references. This is not currently possible in JavaScript. For this reason, the GC will only run in WebGL in situations where the stack is known to be empty (which is currently once after every frame). This is not a problem for most content which deals with managed memory conservatively and has relatively few GC allocations within each frame (you can debug this using the Unity profiler).
WebGL中的一個區別在於垃圾回收(GC)發生的時間點。爲了實施垃圾回收,GC一般須要暫停全部運行中的線程、檢查堆棧和註冊已加載的對象引用。而目前這在JavaScript中還不能實現。由此,僅當堆棧爲空(目前在每一幀後有一次)的時候GC纔會在WebGL中運行。對於保守處理託管內存和在每幀中GC分配相對較少的大多數WebGL內容,這不是問題(您可使用Unity分析器進行調試)。
However, if you had code like the following:
然而,若是您的代碼看起來以下:
string hugeString = "";
for (int i = 0; i < 100000; i++)
{
hugeString += "foo";
}
, then this code would fail running on WebGL, as it would not get a chance to run the GC between iterations of the loop, to free up memory used by all the intermediate string objects - which would eventually cause it to run out of memory in the Unity heap.
則該代碼在WebGL中將沒法運行。由於在for循環中沒有機會運行垃圾回收機制以釋放全部中間字符串對象所使用的內存——這些字符串對象最終會致使代碼用光Unity堆內存。
連接:
https://docs.unity3d.com/540/Documentation/Manual/webgl-memory.html