当前位置:网站首页>[notes] in depth explanation of assets, resources and assetbundles
[notes] in depth explanation of assets, resources and assetbundles
2022-07-04 12:24:00 【Porridge cook_ ninety-nine】
Catalog
Assets、Objects And serialization
2.1 Internal assets and objects
2.2. Reference between objects
2.5. Serialization and instance
2.8. Load large hierarchies (hierarchy)
1.Resources System best practices
2.Resources Correct use of the system
4.3.1 AssetBundle.LoadFromMemoryAsync
4.3.2. AssetBundle.LoadFromFile(Async)
4.3.3.UnityWebRequest 's AssetBundleDownloadHandler
4.3.4. WWW.LoadFromCacheOrDownload
4.4. from AssetBundle Loading assets
The explanation in the manual :
4.4.1. Low level loading details
4.4.2. AssetBundle Dependencies
4.4.3. AssetBundle detailed list
5.2.1. Distribute with the project
5.3. Asset allocation strategy
5.5. AssetBundle variant (Variants)
5.6. Compress or non-compressed ?
take Assets Assigned to AssetBundle
Deepen understanding BuildPipeline.BuildAssetBundles Three parameters of
load AssetBundle And resources
Tools :Unity Asset Bundle Browser tool
The original address of the course :
Assets, Resources and AssetBundles - Unity Learnhttps://learn.unity.com/tutorial/assets-resources-and-assetbundles/?_ga=2.115770310.1168700744.1642556774-152315200.1542532429&tab=overview#5c7f8528edbc2a002053b5a6 Be careful : This tutorial is now deprecated . We now recommend using Addressables. Please also refer to Unity manual
Assets、Objects And serialization
2.1 Internal assets and objects
Assets and UnityEngine.Objects The difference between
Asset It's a on disk file , Stored in Unity Project Assets In the folder . texture 、3D Models or audio clips are a common type of asset . some Assets contain Unity Data in native format , For example, materials . other Assets It needs to be processed into native format , for example FBX file .
UnityEngine.Object Or with uppercase “O” The object of is a group Serialized data , Describe specific instances of resources together . This can be Unity Any type of resource used by the engine , for example mesh, sprite, AudioClip or AnimationClip. All objects are UnityEngine.Object Subclasses of base classes .
Assets and Objects It's a one to many relationship ; in other words , Any given Assets Each file contains one or more Objects.
2.2. Reference between objects
all UnityEngine.Objects Can quote other UnityEngine.Objects. These others Objects It could be the same Asset In the document , It could be something else Asset Imported from the file . for example , A material object usually has one or more references to texture objects . These texture objects are usually from one or more textures Asset file ( for example PNG or JPG) The .
Serialization , These references contain two separate data : file GUID ( File GUID ) And local ID( Local ID ).
file GUID Identify the Asset file .
A local only Local ID identification Asset Every... In the document Object, Because a Asset The file may contain multiple Object. ( Be careful :AA Local ID All other local files that are different from the same asset file ID.)
How to view a material Of File GUID and Local ID :
Open with a text editor material The associated .meta file . Be marked with “guid” The line of appears near the top of the file . This line defines material Asset Of File GUID.
To find out Local ID, Please open in a text editor material file .material The definition of the object is as follows :
--- !u!21 &2100000
Material:
serializedVersion: 3
... more data …
In the example above ,“&” The number after the symbol is material Local ID. If This material object is located by File GUID“abcdefg” Within the identified asset , Then the material object can be uniquely identified as File GUID“abcdefg” and Local ID “2100000” The combination of .
2.5. Serialization and instance
Although the file GUID And local ID Very powerful , But by comparison GUID slowly , And higher performance systems are needed at runtime .
Unity Internal maintenance one cache , Will file GUID And local ID Convert to simple 、 The only integer in the session ( In the internal , This cache is called PersistentManager.) These integers are called example ID, When a new object is registered to the cache , Assign in a simple monotonically increasing order .
cache Maintain a given instance ID、 file GUID And local ID( Define the location of the object source data ) And in memory object instances ( If there is ) Mapping between , bring UnityEngine.Objects Be able to maintain each other's references steadily .
analysis Instance ID quote You can quickly return to this Instance ID Represented by loaded Object. If the target object has not been loaded , You can put the file GUID And local ID Source data parsed as objects , So as to allow Unity Load objects in time .
Startup time ,Instance ID cache Initialize with the following data : All that the project needs immediately Objects( namely : Building Scenes Citation in )、Resources All contained in the folder Objects.
When in Runtime Import new Asset And from the AssetBundle When loading objects , New entries will be added to cache in ( Be careful :“ Runtime Created Asset ” For example —— Created in the script Texture2D object , Such as : var myTexture = new Texture2D(1024,768); ).
Instance ID The entry is only in this case from cache Delete in —— When providing for specific file GUID and Local ID The visit of AssetBundle Be unloaded . When this happens , example ID、 Its documents GUID And local ID The mapping between will be deleted to save memory . If AssetBundle Has been reloaded , Will be for each from this AssetBundle In Object Create a new Instance ID.
On a specific platform , Certain events may force Objects Leave memory . for example , stay iOS On , When App When suspended , graphics Assets Can be from Graphics memory To unload . If these Object From a that has been uninstalled AssetBundle,Unity You cannot reload these Objects Source data for , All extant to these Objects References to will also be invalid . In the previous example , The scene may appear to have invisible meshes or magenta textures .
2.7. Life cycle of resources
It will be loaded automatically in the following cases Object:
- Map to the Object Of Instance ID By Quoting (dereferenced)
- Object Currently not loaded into memory
- Can locate Object Source data for .
You can also use scripts to display loaded objects , By creating objects or calling resource-loading API ( for example AssetBundle.LoadAsset) . When loading objects ,Unity Try to resolve any references (reference), By putting each reference Of file GUID And local ID Convert to Instance ID . When one Object Of Instance ID First time being Quoting when , If the following two conditions are true , Objects will be loaded on demand :
- Instance ID Referenced object At present Not loaded yet
- Instance ID Have It works file GUID And local ID Register in cache
Objects are unloaded in three specific scenes :
Happen when unused Asset When cleaning , The object will be unloaded automatically . This process is triggered automatically , When the scene changes destructively ( namely SceneManager.LoadScene is invoked non-additively) Or script call Resources.UnloadUnusedAssets API when . This procedure only uninstalls Not quoted The object of ;Object It will be uninstalled only in the following cases —— No, Mono A variable holds a reference to it , There are no other existing objects ( live Object) Hold a reference to it . Besides , Please note that , Marked as HideFlags.DontUnloadUnusedAsset or HideFlags.HideAndDontSave The content of will not be uninstalled .
come from Resources The object of the folder can be called Resources.UnloadAsset API Explicit uninstall . Of these objects Instance ID Still valid , And will still contain valid files GUID and LocalID entry . For the use of Resources.UnloadAsset Unloaded Object, If anything Mono Variable or something else Object Hold a reference to it , So once any live references Be dereferenced , The Object Will be reloaded .
come from AssetBundles The object of , When calling AssetBundle.Unload(true) API when , Will automatically uninstall immediately . This will make the object Instance ID Files with GUID And local ID Invalid , And any real-time reference to it will become “(Missing)” quote . stay C# Script , Attempts to access methods or properties of unloaded objects will result in NullReferenceException.
If the AssetBundle.Unload(false), From uninstalled AssetBundle The activities of Object Will not be destroyed , but Unity Will abolish its Instance ID File with GUID And local ID. If these objects are unloaded from memory later and the real-time reference to the unloaded objects still exists ,Unity You will not be able to reload these objects .
2.8. Load large hierarchies (hierarchy)
The serialization Unity GameObjects Hierarchy of ( For example, in serialization prefabs period ), It is important to remember that , Whole The hierarchy will be Completely serialize . in other words , Every... In the hierarchy GameObject and Component Will be represented one by one in the serialized data . This has an interesting effect on the time required to load and instantiate the game object hierarchy .
In creating any GameObject In hierarchy ,CPU Time is spent in several different ways :
- Read Source data ( From storage 、AssetBundle、 the other one GameObject etc. )
- Set new Transforms Between Father and son Relationship
- Instantiation new GameObjects and Components
- On the main thread Wake up the new GameObjects and Components
The time spent in the last three is usually constant , No matter the hierarchy Is from the existing hierarchy Structure cloning , Or load it from storage . however , The time to read the source data increases with serialization to hierarchy Medium Components and GameObjects The number of increases linearly , And multiply it by the speed of the data source .
On all current platforms , from Memory Other places in Reading data Bicong The storage device Loading data is much faster . Besides , The performance characteristics of available storage media vary greatly from platform to platform . therefore , Load on a slower storage platform prefabs when , Read from storage prefabs Serialization of data will take much longer than instantiation prefabs The time it takes . in other words , The cost and storage of loading operations I/O It's about time .
As mentioned earlier , The serialization ( Huge and separate ) During prefabrication , Every GameObject And component data are serialized separately , This may duplicate the data . for example , have 30 Of the same element UI The interface will serialize the same elements 30 Time , So it produces a lot of binary data . When loading , this 30 The data of all game objects and components contained in each of the repeated elements must be read from disk , Then it can be transferred to the newly instantiated object . The file reading time is an important factor in the total cost of instantiating large prefabricated parts .
Large scale hierarchy Should be instantiated in modular blocks , And then stitched together at runtime .
Unity 5.4 Be careful :Unity 5.4 Changed the memory Transform The representation method of . Every root Transform All sub hierarchies of are stored in compact 、 In contiguous memory areas .
When instantiating a new GameObject when , If it is to be set to another immediately hierarchy The children of (reparented into another hierarchy), Please consider using a new GameObject.Instantiate Overloaded variants . Using this overload avoids assigning root transform hierarchy . In the test , This speeds up the time required for the instantiation operation by approximately 5-10%.
MonoScripts
MonoScript Contains three strings : Assembly name 、 Namespace and class name .
When building a project ,Unity take Assets In the folder All loose Script files Compiled into Mono Assembly .Plugins Out of subfolders C# The script is placed in Assembly-CSharp.dll in .Plugins Scripts in subfolders are placed in Assembly-CSharp-firstpass.dll in , wait .
These assemblies, as well as pre built assemblies DLL The file is contained in Unity The final build of the application . They are, too MonoScript The referenced assembly . Unlike other resources ,Unity The... Included in the application All assemblies It's all in When the application starts load Of .
This MonoScript Object Which explains why —— AssetBundle( or Scene、prefab) In fact, it does not include MonoBehaviour Executable code in component . This allows different MonoBehaviours Reference specific shared classes , Even if MonoBehaviours Located in different AssetBundle in .
Resources Folder
Resources The system allows developers to Assets Stored in one or more named Resources In the folder of , And use... At run time Resources API From these Assets Loading or unloading objects .
1.Resources System best practices
Don't use it .
There are several reasons for this strong recommendation :
- Use Resources Folders make fine-grained memory management more difficult
- Resources Improper use of folders will Increase application startup time and Build time
- With Resources Increase in the number of folders , Asset management in these folders becomes very difficult
- Resources The system reduces the ability of the project to deliver customized content to a specific platform , And eliminate the possibility of incremental content upgrade
- AssetBundle Variants yes Unity The main tool for adjusting content according to each device
2.Resources Correct use of the system
There are two specific use cases ,Resources The system can help without hindering good development practice :
- Resources The ease of use of folders makes them an excellent system for rapid prototyping .—— however , When the project enters the full production stage , The use of Resources Folder .
- Resources Folders can be useful in trivial situations , If the content is :
- It is usually required throughout the life cycle of the project
- Not memory intensive (memory-intensive)
- Not easy to patch , Or it doesn't depend on the platform or equipment
- For minimum bootstrap (minimal bootstrapping)
Examples of the second case include MonoBehaviour Single case , Or contain third-party configuration data ScriptableObjects, for example Facebook Applications ID.
3.Resources Serialization
project build after , All are called “Resources” The assets and objects in the folder of will be merged into a serialized file . The file also contains metadata (metadata) And index information , Be similar to AssetBundle. Such as AssetBundle Described in the documentation , This index contains a serialized lookup tree , Used to resolve the name of a given object to its appropriate file GUID And local ID. It is also used to locate objects at specific byte offsets in the body of the serialized file .
On most platforms , Finding data structures is a balanced search tree , Its build time is in O(n log(n)) The rate of growth . This growth has also led to Loading time of index With Resources In the folder Number of objects With the increase of Nonlinear growth .
This operation cannot be skipped , And in When the application starts 、 When the initial non interactive startup screen is displayed (initial non-interactive splash screen) happen . It has been observed , Initialize the include on the low-end mobile device 10,000 Of assets Resources The system will take several seconds , Even though most of the objects contained in the resource folder rarely need to be loaded into the first scenario of the application .
AssetBundle Basics
AssetBundle It's made up of two parts : header (Header) and Data segment (data segment).
The header contains information about AssetBundle Information about , For example, its identifier 、 Compression type and manifest . Listing is a lookup table with object names as keywords . Each entry provides a byte index , The indication is in AssetBundle The location of the given object can be found in the data segment of . On most platforms , This lookup table is implemented as a balanced search tree . say concretely ,Windows and OSX Derivative platform ( Include iOS) Use red and black trees . therefore , The time required to build the manifest will increase with AssetBundle The increase in the number of assets in Linear increase .
4.3. load AssetBundle
There are four different API To load the AssetBundle. The four API Behavior varies according to two criteria :
- AssetBundle yes LZMA Compress 、LZ4 Compressed or uncompressed
- load AssetBundle The platform of
4.3.1 AssetBundle.LoadFromMemoryAsync
Unity The advice is Do not use this API.
this API The maximum amount of memory consumed will be at least AssetBundle Twice the size : One in API Created in native memory , One is being passed on to API In the managed byte array of . therefore , From here API Created AssetBundle The loaded asset will be copied in memory three times : Once in the managed code byte array , Once in AssetBundle In the local memory copy of , For the third time GPU Or in the system memory for the asset itself .
- Instructions in the tutorial : This method retrieves an array of bytes from managed code (C# Medium byte[]) load AssetBundle. It always copies the source data from the managed code byte array to a newly allocated 、 In consecutive native memory blocks . If AssetBundle yes LZMA Compression of the , It will decompress when copying AssetBundle. Uncompressed and LZ4 Compression of the AssetBundle Will be copied verbatim .
- Instructions in the manual : This function takes the form of including AssetBundle Byte array of data . It can also be delivered as needed CRC value . If the bundle uses LZMA Compression way , Will be decompressed at load AssetBundle.LZ4 The compressed package will be loaded in a compressed state .
however , It's not about achieving LoadFromMemoryAsync The only strategy .File.ReadAllBytes(path) It can be replaced by any required procedure to get an array of bytes .
Usage examples :
using UnityEngine;
using System.Collections;
using System.IO;
public class Example : MonoBehaviour
{
IEnumerator LoadFromMemoryAsync(string path)
{
AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
yield return createRequest;
AssetBundle bundle = createRequest.assetBundle;
var prefab = bundle.LoadAsset<GameObject>("MyObject");
Instantiate(prefab);
}
}
4.3.2. AssetBundle.LoadFromFile(Async)
AssetBundle.LoadFromFile It's a efficient API, For from The local store load non-compressed or Data blocks (LZ4) Compression mode AssetBundle, For example, from the hard disk or SD card .
- non-compressed / Block compression (LZ4): Efficient , Load packages directly from disk
- Completely compressed (LZMA): First unzip the package , Then load it into memory
Stand alone on the desktop 、 On consoles and mobile platforms ,API take Load only AssetBundle Of header , And leave the remaining data on disk . AssetBundle The object will load the method when it is called ( for example AssetBundle.Load) Or dereference them InstanceID Load on demand . In this case, no extra memory will be consumed .
stay Unity Editor ,API Will bring the whole AssetBundle Load into memory , It's like reading bytes from disk and using AssetBundle.LoadFromMemoryAsync equally . If in Unity Analyze the project in the editor , this API May result in AssetBundle Memory peak during load . This should not affect the performance of the device , And these peaks shall be retested on the equipment before remedial measures are taken .
Example :
public class LoadFromFileExample : MonoBehaviour {
function Start() {
var myLoadedAssetBundle
= AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
if (myLoadedAssetBundle == null) {
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject");
Instantiate(prefab);
}
}
4.3.3.UnityWebRequest 's AssetBundleDownloadHandler
Script usage guide :
UnityWebRequest There is a specific API Handle AssetBundle.
First , Need to use UnityWebRequest.GetAssetBundle
To create Web request.request After the return , take request Object passed to DownloadHandlerAssetBundle.GetContent(UnityWebRequest)
.GetContent
The call will return AssetBundle object .
After downloading the bundle , You can also do it in DownloadHandlerAssetBundle Class using the assetBundle
attribute , So as to AssetBundle.LoadFromFile
Efficiency loading AssetBundle.
The following example shows how to load a AssetBundle And instantiate these game objects .
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request
= UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
Instantiate(cube);
Instantiate(sprite);
}
More about :
UnityWebRequest API Allows developers to specify exactly Unity How to deal with the downloaded data , And allows developers to eliminate unnecessary memory usage . Use UnityWebRequest download AssetBundle The easiest way to do this is to call UnityWebRequest.GetAssetBundle.
For the purposes of this guide , The classes of interest are DownloadHandlerAssetBundle. Use worker threads , It streams the downloaded data to a fixed size buffer , Then, according to the configuration of the download handler , Spooling buffered data to temporary storage or AssetBundle cache . All of this happens in native code , Eliminates the risk of expanding the managed heap . Besides , This download handler does not retain native code copies of all downloaded bytes , This further reduces downloads AssetBundle Memory overhead .
LZMA Compression of the AssetBundle Will unzip and use... During download LZ4 Compress for caching . Can be set by Caching.CompressionEnabled Change this behavior .
When the download is complete , Download handler assetBundle Property provides support for downloading assetBundle The interview of , It's like downloading AssetBundle It's up-regulated AssetBundle.LoadFromFile equally .
If to UnityWebRequest Object provides cache information , And requested AssetBundle Already in existence Unity The cache , be AssetBundle Will be available immediately , And this API Operation and AssetBundle.LoadFromFile identical .
4.3.4. WWW.LoadFromCacheOrDownload
Given that this method is outdated , Will be deprecated in future versions ,Unity Suggest Use Unity 2017.1 Or later developers should migrate to UnityWebRequest. Check by yourself if necessary manual .
4.3.5 Suggest
Usually , Use as much as possible AssetBundle.LoadFromFile. This API At speed 、 Disk usage and runtime memory usage are the most effective .
4.4. from AssetBundle Loading assets
UnityEngine.Objects You can use three different API from AssetBundle load , these API Are attached to AssetBundle object , They have synchronous and asynchronous variants :
- LoadAsset (LoadAssetAsync)
- LoadAllAssets (LoadAllAssetsAsync)
- LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)
these API Of synchronize versions It's always better than Asynchronous version fast At least one frame . Asynchronous loading will load multiple objects per frame , Until their time slice limits .
- LoadAllAssets - Load multiple independent UnityEngine.Objects Use LoadAllAssets. Only when you need to load AssetBundle Medium Most of the Or all objects .LoadAllAssets Than multiple separate calls LoadAsset Hurry up . therefore , If you want to load a large number of assets at one time , But no more than AssetBundle Of 66%, Please consider that AssetBundle Split into several smaller bundle And use LoadAllAssets.
- LoadAssetWithSubAssets - When loading a composite resource containing multiple embedded objects Use , For example, with embedded animation FBX Model or a collection of sprites with multiple sprites embedded in it . If you need to load Objects All from the same Asset, But with many other irrelevant Objects Stored in AssetBundle in , Use this API.
- For any other case , Please use LoadAsset or LoadAssetAsync.
The explanation in the manual :
General code snippets :
T objectFromBundle = bundleObject.LoadAsset<T>(assetName);
Synchronization method
// Load a single GameObject :
GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);
// Load all resources :
Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
Asynchronous methods
Asynchronous method returns AssetBundleRequest. Before accessing resources , You need to wait for this operation to complete . load resources :
// Load a single object :
AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
yield return request;
var loadedAsset = request.asset;
// Load multiple objects :
AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request;
var loadedAssets = request.allAssets;
After loading resources , It's time to start ! It can be like using Unity Use the loaded object just like any object in .
4.4.1. Low level loading details
synchronous AssetBundle.Load Method will pause the main thread , Until the object is loaded . They will also time slice the object load , So that object integration will not take more than a certain number of milliseconds of frame time . The number of milliseconds is determined by the attribute Application.backgroundLoadingPriority Set up :
- ThreadPriority.High: Maximum per frame 50 millisecond
- ThreadPriority.Normal: Maximum per frame 10 millisecond
- ThreadPriority.BelowNormal: Maximum per frame 4 millisecond
- ThreadPriority.Low: Maximum per frame 2 millisecond .
4.4.2. AssetBundle Dependencies
【manual page】https://docs.unity3d.com/Manual/AssetBundles-Dependencies.html Be a father AssetBundle There are one or more UnityEngine.Objects Reference to another AssetBundle One or more of UnityEngine.Objects when , One AssetBundle Depend on another AssetBundle.
If one UnityEngine.Object Include for another UnityEngine.Object References to , And another one. Object Not assigned in any AssetsBundle in , There will be no dependencies . under these circumstances , In the build AssetBundle when , A copy of the objects that the package depends on will be copied to the package .( If multiple objects in multiple packages contain references to the same object , And this object is not assigned to any Bundle in , that , Each that depends on this object Bundle Will create a copy of this object , And package it into the built AssetBundle in .)
If public resources are allocated to separate AssetBundle , Be careful about dependencies . especially , If you only use one Prefab To instantiate a module , Materials will not be loaded .「 chart : There is no material loaded Prefab」
To solve this problem , You should load the AssetBundle Before , First the Materials Of AssetBundle Load into memory .
load AssetBundle The order is not important . however , In the load Object Before myself , Load all containing Object Dependent AssetBundle Very important .Unity Will not attempt to automatically load dependencies .
- stay Unity Editor : AssetBundle Dependencies It can be done by AssetDatabase API Inquire about .AssetBundle Distribute and Dependency relationship Can pass AssetImporter API Access and change .
- At run time : Unity An optional API, For loading in AssetBundle Dependency information generated during build , Through a ScriptableObject Of AssetBundleManifest API.
for example :
hypothesis texture of material A quote texture B. texture of material A To be packed into AssetBundle 1 in , texture B To be packed into AssetBundle 2 in .
In this case , In from AssetBundle 1 Loading material A Before , You have to load AssetBundle 2 .
This does not mean that you have to load AssetBundle 1 Load before AssetBundle 2, Or have to start from AssetBundle 2 Load textures explicitly B. In from AssetBundle 1 Load material A Load before AssetBundle 2 That's enough .
however , load AssetBundle 1 when ,Unity Will not automatically load AssetBundle 2. This must be done manually in the script code .
4.4.3. AssetBundle detailed list
load AssetBundle Checklists can be very useful . Especially in dealing with AssetBundle When it comes to dependency .
To get available AssetBundleManifest object , Need to load another AssetBundle( The one with the same name as its folder ) And load AssetBundleManifest Object of type .
The operation method of loading the list itself is the same as AssetBundle Any other resources in are exactly the same :
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
thus , have access to manifest Object to get information about what you build AssetBundle Information about , Include AssetBundle Dependency data for 、 Hash data and variant data . manifest Object can dynamically find loading dependencies . Suppose we want to be named “assetBundle” Of AssetBundle Load all dependencies :
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("assetBundle"); // Pass the name of the bundle you want to depend on .
foreach(string dependency in dependencies)
{
AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}
Explanation in the tutorial :
When using BuildPipeline.BuildAssetBundles API perform AssetBundle When building pipelines ,Unity Will serialize one Object, It contains every AssetBundle Of information . It is stored in a separate AssetBundle in , There is only one AssetBundleManifest Type of Object.
Store this Asset Of AssetBundle, It is similar to the AssetBundle The folder has the same name . If the project puts AssetBundles Build to (projectroot)/build/Client/ A directory of , Contains the list AssetBundle Will be saved as (projectroot)/build/Client/Client.manifest.
Containing the list AssetBundle It can be like any other AssetBundle Also loaded 、 Cache and unload .
AssetBundleManifest The object itself provides GetAllAssetBundles API To list all built at the same time as the list AssetBundles, And two query specific AssetBundle Dependency approach :
- AssetBundleManifest.GetAllDependencies Return to one AssetBundle All levels of dependencies , Include AssetBundle Direct children of 、 Dependencies of its children, such as children .
- AssetBundleManifest.GetDirectDependencies Return only AssetBundle Direct children of
Please note that , these two items. API Both allocate string arrays . therefore , They should only be used with caution , Not in the performance sensitive part of the application lifecycle .
4.4.4. Suggest
in many instances , It's best when players enter the performance critical area of the application ( For example, the main game level or world ) Load before As many objects as you need . This is particularly important on mobile platforms , On these platforms , Access to local storage is slow , And in play-time load 、 Memory fluctuations caused by unloading objects Will trigger GC.
5.AssetBundle Usage mode
5.1 Manage loaded assets
In a memory sensitive environment, it is important to carefully control the size and number of loaded objects . When removing objects from the active scene ,Unity Objects are not automatically unloaded . Asset liquidation (Asset cleanup) Trigger at a specific time , It can also be triggered manually .
AssetBundles Itself must be carefully managed . from Files on local storage Supported AssetBundle( Included in Unity In the cache , Or through AssetBundle.LoadFromFile Loaded ) With minimal memory overhead , Rarely consume more than a few dozen KB. however , If there's a lot of AssetBundle, This cost will still be a problem .
Because most projects allow users to re experience content ( For example, play level again ), So know when to load or unload AssetBundle It's very important . If AssetBundle Improper uninstallation , It may cause duplicate objects in memory . In some cases , Uninstall incorrectly AssetBundle It will also lead to unexpected performance , For example, resulting in texture loss .
Manage assets and AssetBundle when , The most important thing is to understand the call AssetBundle.Unload when , Parameters “unloadAllLoadedObjects” Use true and false The difference in behavior .
this API The calling... Will be uninstalled AssetBundle Header information for . unloadAllLoadedObjects Parameters determine whether to uninstall from AssetBundle All objects instantiated . If set to true, It comes from AssetBundle All objects of will also be unloaded immediately —— Even if they are currently being used in the active scene .
for example , Suppose the material M It's from AssetBundle AB Loaded , And suppose M Currently in the active scene .
If the AssetBundle.Unload(true), be M Will be removed from the scene 、 Destroy and unload . however , If the AssetBundle.Unload(false), be AB Of header Information will be uninstalled , but M Will remain in the scene , It still works . call AssetBundle.Unload(false) Will disconnect M and AB Links between . If you load again later AB, be AB It contains Objects A new copy of will be loaded into memory .
If you load again later AB, Will be reloaded AssetBundle header A new copy of the information . however ,M Not from this new AB Load in the copy . Unity Not in AB and M Create any links between new copies of .
If the AssetBundle.LoadAsset() To reload M,Unity Will not M The old copy of is interpreted as AB Examples of data in . therefore ,Unity Will load M A new copy of , And there will be two identical M copy .
For most projects , This kind of behavior is not desirable . Most projects should use AssetBundle.Unload(true) And adopt a method to Make sure Objects No repetition . Two common methods are :
- There are clearly defined points in the application lifecycle , Used to uninstall temporary AssetBundle, For example, between levels or in Loading page . This is the simplest and most common choice .
- Maintain the reference count of a single object and unload only when none of its constituent objects are in use AssetBundle. This allows applications to unload and reload individual objects without copying memory .
If the application must use AssetBundle.Unload(false), So single Objects There are only two ways to uninstall :
Eliminate all references to unwanted objects , Including scenarios and code . Then call Resources.UnloadUnusedAssets.
Load the scene as non attached (non-additively). This will destroy all objects in the current scene and automatically call Resources.UnloadUnusedAssets.
If the project has clearly defined points , Allows users to wait for objects to load and unload , For example, between game modes or levels , These points should be used to unload as many objects as needed and load new objects .
The easiest way is to package the discrete blocks of the project into the scene , Then build these scenarios together with all their dependencies into AssetBundles in . Then the application can enter “Loading” scene , Completely uninstall the... That contains the old scene AssetBundle, Then load the... That contains the new scene AssetBundle.
Although this is the simplest process , But some projects require more complex AssetBundle management . Because each project is different , Therefore, there is no universal AssetBundle Design patterns .
When deciding how to group objects into AssetBundle In the middle of the day , If they have to be loaded or updated at the same time , It's usually best to tie them to AssetBundle in . for example , Consider one RPG game . Individual maps and transition animations can be grouped into... By scene AssetBundle in . But some of the Objects In most scenarios , You can build a AssetBundle To provide vertical drawing 、 In the game UI And different character models and textures , Then group the following objects and assets into the second AssetBundle in , Load at startup and remain loaded throughout the life of the application .
Another problem may arise , When one AssetBundle After being unloaded , If Unity It has to come from this AssetBundle Reload an object in . At this time , Reload will fail , And the object will act as (Missing) Object appears in Unity The editor's hierarchy In the view .
This mainly happens in Unity When you lose and regain control of its graphics context , For example, when mobile applications pause or users lock their PC when . under these circumstances ,Unity Textures and shaders must be re uploaded to GPU. If the source of these assets AssetBundle Unavailable , The application renders the objects in the scene magenta .
5.2.1. Distribute with the project
Provided with the project AssetBundle Is the easiest way to distribute them , Because it does not require additional download management code . The project may include AssetBundle There are two main reasons :
- Reduce project construction time and allow simpler iterative development . If these AssetBundle There is no need to update separately from the application itself , You can do this by AssetBundle Stored in Streaming Assets in , send AssetBundle Included in application . See below Streaming Assets part .
- Release an initial revision of updatable content . This is usually done to save the end user time after the initial installation , Or as the basis for future repair . In this case ,Streaming Assets Not ideal . however , If you cannot write a custom download and caching system , The initial revision of the updatable content can be changed from Streaming Assets Load into Unity In cache ( See the cache startup section below ).
5.2.1.1. Streaming Assets
If you want to install Unity Application time , It contains any kind of content ( Include AssetBundle), The simplest way is : Before building the project , Build content into /Assets/StreamingAssets/ In the folder . Build time StreamingAssets Anything contained in the folder will be copied into the final application .
At run time ,StreamingAssets The full path of the folder on the local storage You can use the properties Application.streamingAssetsPath visit . Then on most platforms , Can pass AssetBundle.LoadFromFile load AssetBundle.
Be careful :StreamingAssets Not writable on some platforms . If you need to update the project after installation AssetBundle, Please use WWW.LoadFromCacheOrDownload Or write a custom downloader .
5.3. Asset allocation strategy
Decide how to put the project Assets Divided into AssetBundle Not simple . It is tempting to adopt a simple strategy , For example, all objects are placed in a that contains only themselves AssetBundle, Or just use one AssetBundle, But these solutions have obvious disadvantages :
- AssetBundle too little / Too much ...
- Add runtime Memory usage
- increase loading Time for
- Need more downloads
- Increase build time
- Complicate development
- Increase total download time
Decide how to group objects into AssetBundles It's critical , The main strategy is :
- Logical entity grouping —— according to Assets The project function part represented allocates resources to AssetBundle. for example :
- One 「UI Interface 」 be-all texture 、 Layer data etc.
- One or a group of 「 role 」 be-all Model 、 Animation
- Some consist of multiple levels 「 Shared scenery 」 Of texture 、 Model
- object type —— Put similar types of resources ( For example, audio tracks or language localization files ) Assigned to a AssetBundle.
- To build for multiple platforms AssetBundle, Type grouping is one of the best strategies .
- for example , If audio compression is set to Windows and Mac Exactly the same on the platform , All audio data can be packaged into AssetBundle , And reuse these packages . Shaders are often compiled with more platform specific options , Therefore Mac Built Shader The package may not work in Windows Reuse on .
- Besides , This method is very suitable for AssetBundle And Unity Player More versions are compatible , Because the texture compression format and settings are changed less frequently than code scripts or prefabricated parts .
- Concurrent Content —— Package the resources that need to be loaded and used at the same time .
- These types of packages can be used for level based games ( Each of these levels contains completely unique characters 、 texture 、 Music, etc ).
The most common use case is for scenario based bundles , It should include most or all of the scenario dependencies .
- Sometimes you may want to ensure AssetBundle One of the resources in is used simultaneously with other resources in the package . If 「 Contract issuance 」 One in Asset It's a dependency , This will result in a significant increase in loading time , Because you have to for this one Asset Instead, download the entire bundle .
- These types of packages can be used for level based games ( Each of these levels contains completely unique characters 、 texture 、 Music, etc ).
Please note that , You can definitely mix these strategies according to your needs , And it should also be done . Using the optimal strategy can greatly improve the efficiency of the project .
No matter what strategy you follow , The following additional tips will help you take control :
- Split frequently updated objects and rarely changed objects into different AssetBundle in
- It will be possible Load at the same time Objects of are grouped . Such as models and their textures and animations
- If you find more than one AssetBundle Multiple objects in depend on another completely different AssetBundle Individual resources in , Please put Dependencies Move to a separate AssetBundle.
- If more than one AssetBundle Quote others AssetBundle The same set of resources in , A valuable approach might be to pull these dependencies into a share AssetBundle To reduce repetition .
- If two groups of objects cannot be loaded at the same time ( For example, standard definition resources and HD resources ), Please make sure they are in their respective AssetBundle in .
- If one AssetBundle There are less than 50% Resources of are often loaded at the same time , Please consider splitting the bundle .
- Consider multiple 「 smaller 、 But content is often loaded at the same time 」 Of AssetBundle Merge , For example, less than 5 To 10 A resource .
- If a group of objects are just different versions of the same object , Please consider using AssetBundle Variants.
5.4. Common pitfalls
5.4.1. Duplicate assets
When the object is built to AssetBundle In the middle of the day ,Unity 5 Of AssetBundle The system will find all the dependencies of the object . This is done using the resource database . This dependency information is used to determine whether it is contained in AssetBundle Set of objects in .
Explicitly assigned to AssetBundle The object of will only be built to this AssetBundle in .“ Explicit allocation ” Refer to : Object's AssetImporter Of assetBundleName Property is set to a non empty string .
Anything that is not explicitly assigned to AssetBundle Objects in the , Will be included in all 「 contain ( One or more ) Quoted the “ Unmarked object ” The object of 」 Of AssetBundle in .
for example , If you assign two different objects to two different AssetBundle, But they all refer to a public dependent object , Then the dependent object will be copied to two AssetBundle in . Replicated dependencies will also be instantiated , This means that two copies of the dependent object will be treated as different objects with different identifiers . This will increase the application AssetBundle The total size of . If the application loads its two parent objects , This also causes two different copies of the object to be loaded into memory .
There are several ways to solve this problem :
Make sure to build to different AssetBundle Objects in do not share dependencies . Any object that shares dependencies can be placed in the same AssetBundle in , Instead of copying their dependencies .
This approach is usually not applicable to projects with many shared dependencies . It will generate large monomers AssetBundle, You must rebuild and re download frequently , This is neither convenient nor efficient .
take AssetBundle piecewise , So that two shared dependencies will not be loaded at the same time AssetBundle.
This approach may be applicable to some types of projects , For example, level based games . however , It still adds items unnecessarily AssetBundle Size , And increased build time and load time .
Public resources ( For example, materials ) Assigned to their own AssetBundle. This completely eliminates the risk of duplicate assets , But it also introduces complexity . The application must track AssetBundle Dependencies between , And make sure to call any AssetBundle.LoadAssetAPI Before , The correct AssetBundle.
Object dependencies pass AssetDatabase API Tracking ( Belong to UnityEditor Namespace ). As namespace implies , this API Only in Unity Available in the editor , Not available at runtime . AssetDatabase.GetDependencies It can be used to locate and specify Object or Asset All of the Direct dependencies . Please note that , These dependencies may have their own dependencies . Besides ,AssetImporter API It can be used to query which... Any specific object is assigned to AssetBundle.
By combination AssetDatabase and AssetImporter API, You can write an editor script , To make sure that a AssetBundle All direct or indirect dependencies of are assigned AssetBundle, Or not two AssetBundle The share has not been assigned to AssetBundle The dependencies of . Due to the memory cost of copying assets , It is recommended that all projects have such scripts .
5.4.2. The elf atlas repeats
The following section will introduce Unity 5 The strange behavior of the resource dependency calculation code in combination with the automatically generated wizard atlas .
whatever Automatically generated elf atlas Will be associated with the Sprite Objects are assigned to the same AssetBundle.*(automatically-generated sprite atlas, Personal understanding is to use sprite packer Generated atlas , Instead of making it externally and importing unity The atlas of China )
- If Sprite Objects Assigned to multiple AssetBundle, Then the elf atlas will not be assigned to AssetBundle , It will be copied .
- If Sprite Objects Not assigned to AssetBundle, The elf atlas will not be assigned to AssetBundle.
To ensure that the elf atlas is not repeated , Please check that all sprites marked in the same sprite graph set are assigned to the same AssetBundle.
5.5. AssetBundle variant (Variants)
AssetBundle A key feature of the system is the introduction of AssetBundle Variants. The purpose of the variation is to allow the application to adjust its content to better adapt to its running environment . Variants are allowed to be different AssetBundle The difference in the document UnityEngine.Object In the load Objects、 analysis Instance ID When referencing , Is shown as “ identical ” object . conceptually , It allows two UnityEngine.Object It seems to share the same file GUID And local ID, And through the string Variant ID Identify the actual... To load UnityEngine.Object.
The system has two main use cases :
Variations simplify the AssetBundle Loading .
Example : Building a system might create a AssetBundle, It includes the application to stand-alone DirectX11 Windows Build high resolution textures and complex shaders , And another for Android With lower fidelity content AssetBundle. At run time , Resource loading of the project (resource loading) The code can load the appropriate AssetBundle Variant, Pass on to AssetBundle.Load API The object name of does not need to be changed
Variations allow applications to Use Different hardware Of The same platform On load Different content .
This is the key to supporting a variety of mobile devices . iPhone 4 It is impossible to display the latest in any actual application iPhone Same content fidelity . stay Android On ,AssetBundle Variants It can be used to solve the problem of screen aspect ratio and DPI The huge fragmentation problem .
5.5.1. Limit
AssetBundle Variant A key limitation of the system is : It requires different Assets structure Variants. Even though these Assets The only change between them is their import settings . If you take a Texture Build to Variant A and Variant B in 、 The only difference is Unity A specific texture compression algorithm selected in the texture importer ,Variant A and Variant B It still has to be completely different Assets. This means variants A And variants B It must be a separate file on disk .
This limitation complicates the management of large projects , Because multiple copies of a particular asset must be kept under source control . When developers want to change Asset When , Must update Asset All copies of . There is no built-in solution to this problem .
Most teams have achieved it in their own way AssetBundle variant . This is through 「 Building AssetBundle The filename is followed by a clearly defined suffix 」 To complete , In order to identify a given AssetBundle The specific variant represented . Custom code programmatically , Building these AssetBundle when , Change what it contains Assets Import settings for . Some developers have extended their custom systems , In order to be able to change the parameters of the components attached to the preform .
5.6. Compress or non-compressed ?
Is it compressed? AssetBundle There are several important factors to consider , These include :
- Loading time : from The local store / cache (local storage or a local cache.) When loading , Compared with compressed AssetBundle, Uncompressed AssetBundle The loading speed of is much faster .
- Build time :LZMA and LZ4 Very slow when compressing files ,Unity Editor Process continuously AssetBundle. Have a lot of AssetBundle Your projects will spend a lot of time compressing them .
- Application size : If AssetBundles Provided with the application , Compressing them reduces the total size of the application . perhaps , You can download it after installation AssetBundle.
- Memory Use : stay Unity 5.3 Before ,Unity All decompression mechanisms need to compress the whole before decompression AssetBundle Load into memory . If memory usage is important , Please use uncompressed or LZ4 Compression of the AssetBundle.
- Download time : Only in AssetBundle It's big Or users are in an environment with limited bandwidth ( For example, download on a low-speed or metered connection ) when You need to compress . If there are only dozens M The data of is transmitted to PC, Maybe you don't need to compress .
5.6.1.Crunch Compress
Mainly used by Crunch Of compression algorithm DXT-compressed textures Composed of Bundle Should be built as non-compressed .
Contents of the manual
take Assets Assigned to AssetBundle
The specified Asset Assigned to AssetBundle, Please perform the following steps :
- stay Project Select in the view to assign to Bundle Of Asset.
- stay Inspector Check the object , stay Inspector The bottom of , There is a section for allocation AssetBundles and Variants. The drop-down menu on the left is used to assign AssetBundle, The drop-down menu on the right is used to assign Variants.
- Click None , You can display the currently registered AssetBundle name ; Click on New Create a new AssetBundle.
- Enter what you want AssetBundle name . Be careful :AssetBundle The name supports some type of folder structure , It depends on what you enter . To add subfolders , Please use
/
Separate folder names . for example , Use AssetBundle nameenvironment/forest
, Will be inenvironment
Create a folder namedforest
Bundle for . - Once you choose or create one AssetBundle name , You can repeat this process to assign or create Variant name ( if necessary ). Variant The name is not build AssetBundles Necessary .
structure AssetBundle
stay Assets Create a folder called Editor Folder , And put the script containing the following contents in this folder :
using UnityEditor;
using System.IO;
public class CreateAssetBundles
{
[MenuItem("Assets/Build AssetBundles")]
static void BuildAllAssetBundles()
{
string assetBundleDirectory = "Assets/AssetBundles";
if(!Directory.Exists(assetBundleDirectory))
{
Directory.CreateDirectory(assetBundleDirectory);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory,
BuildAssetBundleOptions.None,
BuildTarget.StandaloneWindows);
}
}
This script will be in Assets Create a menu named Build AssetBundles The menu item of , This menu item will execute the code in the function associated with this tag . single click Build AssetBundles when , Will follow build The dialog box displays a progress bar . This will get you all tagged up AssetBundle Name Assets, And put them in assetBundleDirectory
In the folder indicated .
Successfully constructed AssetBundle after , You might notice AssetBundles The directory contains more files than originally expected . To be precise , There are more 2*(n+1) File . Let's take a moment to learn more about BuildPipeline.BuildAssetBundles
Results .
For each... Specified in the editor AssetBundle, You can see one with AssetBundle name +“.manifest” The file of .
There is another extra Bundle and manifest The name of is different from any previously created AssetBundle, Instead, use the directory where it is located ( That's all AssetBundle Of build Catalog ) The same name . This is the manifest package (Manifest Bundle).
Deepen understanding BuildPipeline.BuildAssetBundles Three parameters of
- Assets/AssetBundles: This is a AssetBundle Directory to output to . You can change it to any directory you need , Just make sure it's in build The folder actually existed before .
- BuildAssetBundleOptions: Although you can follow Changes in demand Free combination
BuildAssetBundleOptions
, But there are three specificBuildAssetBundleOptions
Can handle AssetBundle Compress :None
(LZMA Compress )
LZMA Format compression . It can get Minimum File size , But due to the need to decompress , Loading time Slightly longer .
LZMA Ask for in Bundle Before using , Need to decompress . in other words , To use any resource in the package , You must decompress first The whole package .
After decompressing , The package will use LZ4 The compression method is to recompress on the disk . It is best to use it in the following cases : Using one asset in the bundle means that all assets will be loaded , Some use cases of this bundle are to package all resources of roles or scenarios .Suggest : take LZMA Compress Only used for 「 Download for the first time from a remote host AssetBundle when 」, Because it compresses the smallest file .
adopt UnityWebRequestAssetBundle Loaded LZMA Of AssetBundle Will automatically recompress to LZ4 , And cache it on the local file system . If you download and store the package in other ways , You can use AssetBundle.RecompressAssetBundleAsync API Recompress it .
- File minimum
- Load slowest
- Before using , You need to decompress the whole package
UncompressedAssetBundle
( No compression )
The data is completely uncompressed .
shortcoming : File download size increases . advantage : The loading time after downloading will be much faster .
- The file is the largest
- Load fastest
- No need to decompress
ChunkBasedCompression
(LZ4 Compress )
LZ4 Compression method . After the compression , File size ratio LZMA Big , But not like LZMA Then you need to decompress the whole package to use .
LZ4 Use a block based algorithm , Allow by segment or “ block ” load AssetBundle. Decompress a single block to use the included resources , Even if it's time to AssetBundle Other blocks in the are not decompressed and will not be affected .
The loading time is roughly the same as that of uncompressed , The additional advantage is to reduce the size of the disk .
- Smaller files
- Loading is fast
- Just decompress what you need “ block ”, Not the whole package
- BuildTarget: Here we tell about building pipelines , We're going to put these AssetBundle For which target platform . stay BuildTarget API A list of available explicit build targets can be found in the reference . however , If you don't want to hard code in your build goals , Please make full use of
EditorUserBuildSettings.activeBuildTarget
, It will automatically find the currently set target construction platform , And build AssetBundle.
load AssetBundle And resources
If you want to load from local storage , Please use AssetBundles.LoadFromFile
API, As shown below :
public class LoadFromFileExample : MonoBehaviour {
void Start() {
var myLoadedAssetBundle
= AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
if (myLoadedAssetBundle == null) {
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
Instantiate(prefab);
}
}
LoadFromFile need bundle Path to file .
If you are hosting AssetBundle And you need to download them into your application , Please use UnityWebRequestAssetBundle API. example :
IEnumerator InstantiateObject()
{
string url = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request
= UnityEngine.Networking.UnityWebRequest.GetAssetBundle(url, 0);
yield return request.Send();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
Instantiate(cube);
Instantiate(sprite);
}
GetAssetBundle(string, int)
Use AssetBundle The location of URL and The version of the package you want to download . This example still points to a local file , but string url
Can point to hosting AssetBundle Any of the URL.
UnityWebRequest Class has a specific handle to handle AssetBundle:DownloadHandlerAssetBundle
, Available upon request AssetBundle.
Either way , Now you can visit AssetBundle Object . For this object, you need to use LoadAsset<T>(string)
, This function requires that you try to load Asset The type of T
, And the name of the object in the package ( As string). It will return you from AssetBundle Any object loaded . These returned objects , You can use it like Unity Use them like any object in . for example , If you want to create one in the scene GameObject, Just call Instantiate(gameObjectFromAssetBundle)
.
This machine uses AssetBundlehttps://docs.unity3d.com/cn/2019.4/Manual/AssetBundles-Native.html
Tools :Unity Asset Bundle Browser tool
Download link :Asset Bundle Browserhttps://github.com/Unity-Technologies/AssetBundles-Browser
Installation steps :
- open Unity [Package Manager] ( menu : Windows > Package Manager).
- Click on the top left + (Add) Button
- choice Add package from git URL…
- Input URL:
https://github.com/Unity-Technologies/AssetBundles-Browser.git
- Click on Add.
Package Manager Download and install This bag “master” Branch .
Instructions page :
边栏推荐
- Number and math classes
- 2021 annual summary - it seems that I have done everything except studying hard
- [directory] search
- Exceptions and exception handling
- Realize cross tenant Vnet connection through azure virtual Wan
- [Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 8
- netstat
- MySQL performance optimization index
- Dos and path
- Googgle guava ImmutableCollections
猜你喜欢
Enter the smart Park, and change begins here
TCP fast retransmission sack mechanism
SAP ui5 date type sap ui. model. type. Analysis of the display format of date
The detailed installation process of Ninja security penetration system (Ninjitsu OS V3). Both old and new VM versions can be installed through personal testing, with download sources
Application of slice
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 15
Ternsort model integration summary
13、 C window form technology and basic controls (3)
Tableau makes data summary after linking the database, and summary exceptions occasionally occur.
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 17
随机推荐
Haproxy cluster
MYCAT middleware installation and use
Memory computing integration: AI chip architecture in the post Moorish Era
Entitas learning [iv] other common knowledge points
IO stream ----- open
Single spa, Qiankun, Friday access practice
DDS-YYDS
How to create a new virtual machine
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 17
Introduction of network security research direction of Shanghai Jiaotong University
2021 annual summary - it seems that I have done everything except studying hard
2020 Summary - Magic year, magic me
. Does net 4 have a built-in JSON serializer / deserializer- Does . NET 4 have a built-in JSON serializer/deserializer?
TCP slicing and PSH understanding
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 24
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 5
Common built-in modules
Lvs+kept highly available cluster
Login operation (for user name and password)
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 8