Unity3D中Texture2D.LoadRawTextureData引发客户端内存暴涨问题求助
Alright, let's break down why your client's memory is skyrocketing to 8GB+ and fix this issue properly.
The Root Causes
First, let's unpack what's going wrong in your current code:
- Frequent Texture Creation/Destruction: Every call to
DisplayFramecreates a brand newTexture2Dand immediately destroys it. Even though you callDestroy(texture), Unity doesn't free memory instantly—CPU-side objects wait for garbage collection (GC), and GPU-side texture memory takes even longer to release. This constant churn leads to massive memory buildup as hundreds/thousands of orphaned texture objects pile up before GC runs. - Black Screen After
frame = null: When you destroy the texture and setframe = null, your renderer's material is left referencing a destroyed texture asset. With no valid texture data to display, the screen turns black.
The Optimal Fix: Reuse a Single Texture
The best solution is to reuse a single texture instance instead of creating/destroying one every frame. Texture creation is an expensive operation, and reusing eliminates GC pressure and memory bloat entirely.
Here's how to refactor your client code:
Step 1: Cache the Texture and Renderer
Declare class-level variables to hold your reusable texture and renderer (avoids repeated GetComponent<Renderer>() calls):
private Texture2D _screenTexture; private Renderer _meshRenderer;
Step 2: Initialize Once in Awake/Start
Set up your texture and renderer once when the script loads, not every frame:
void Awake() { // Cache the renderer to avoid repeated lookup overhead _meshRenderer = GetComponent<Renderer>(); // Create the texture once with initial screen dimensions _screenTexture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); }
Step 3: Update the Reusable Texture in DisplayFrame
Modify DisplayFrame to update the existing texture instead of creating a new one. We'll also add a check to handle server screen resolution changes:
void DisplayFrame(byte[] frame) { // Guard clause for failed initialization if (_screenTexture == null) { _screenTexture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); } // Recreate texture if server screen size changed if (_screenTexture.width != Screen.width || _screenTexture.height != Screen.height) { Destroy(_screenTexture); _screenTexture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); } // Load new frame data into the existing texture _screenTexture.LoadRawTextureData(frame); _screenTexture.Apply(); // Assign updated texture to the material _meshRenderer.material.mainTexture = _screenTexture; ScreenUpdate = true; // Optional: Clear frame reference to help GC clean up faster frame = null; }
Step 4: Clean Up On Script Destruction
Only destroy the texture when the script is unloaded to avoid memory leaks:
void OnDestroy() { if (_screenTexture != null) { Destroy(_screenTexture); } }
Additional Optimizations
- Sync Screen Dimensions: Instead of relying on client
Screen.width/height, have the server send its screen resolution once during initial connection (or with each frame if it can change). This ensures your client's texture always matches the server's frame size. - Limit Update Frequency: If you're sending frames at 60+ FPS, throttle updates to 30 FPS (or whatever your use case allows) to reduce CPU/GPU load and memory overhead.
- Check for Unintended References: Ensure no other parts of your code hold onto the
byte[] framearray—this can prevent GC from cleaning up that memory.
Verify the Fix
After making these changes, open the Unity Profiler's Memory panel. You'll see texture memory stays at a consistent, low value instead of climbing endlessly. GC events will also drop drastically, improving overall performance.
内容的提问来源于stack exchange,提问作者pookie

