我正在构建一个使用Selenium Webdriver的Unity应用程序,我在另一个线程中启动了无头浏览器(chromedriver)。在该线程中,我继续拍摄无头浏览器中显示的屏幕快照,并将其存储在字节数组中。 在主线程中,我必须使用该字节数组来制作Unity可以理解的图像(Texture2D)。 我启动了该应用程序,它工作了一段时间,但是过了一段时间,应用程序崩溃了。崩溃文件说:
UnityPlayer.dll在模块中导致访问冲突(0xc0000005) 0023:105311be的UnityPlayer.dll。
错误发生在2020-07-30_150418。 C:\ Codes \ Apps \ MyApp \ MyApp.exe,由Fabio运行。
正在使用94%的内存。
0 MB物理内存[423 MB可用空间]。
0 MB分页文件[1990 MB可用]。
0 MB用户地址空间[108 MB可用空间]。
写入位置007e7200导致访问冲突。
应用程序启动后立即启动第二个线程和方法“ LoadImage”(作为Coroutine)
获取屏幕截图的代码:
public async Task ScreenShotBrowser()
{
//await Task.Yield();
while (isBrowserOpen)
{
Screenshot screenshot = ssdriver.GetScreenshot(); //Selenium stuff
lock (imgArray)
{
imgArray = screenshot.AsByteArray;
}
Thread.Sleep(100);
}
}
将图像加载到统一材质中
IEnumerator LoadImage()
{
while (!isBrowserOpen) { yield return new WaitForSecondsRealtime(0.1f); } // ugly code, but avoid freezing
while (isBrowserOpen)
{
lock (imgArray)
{
mat.mainTexture = loadTexture(imgArray);
}
yield return new WaitForSecondsRealtime(0.1f);
}
}
private Texture2D loadTexture(byte[] imageArray)
{
Texture2D tex = new Texture2D(1, 1);
lock (imageArray)
{
tex.LoadImage(imageArray);
}
return tex;
}
预先感谢
答案 0 :(得分:1)
不确定这是否是问题所在,但我认为这里确实发生了内存不足的情况。
private Texture2D loadTexture(byte[] imageArray)
{
Texture2D tex = new Texture2D(1, 1);
lock (imageArray)
{
tex.LoadImage(imageArray);
}
return tex;
}
这会经常在您的应用程序中创建并加载新的Texture2D
。但是,即使不再引用纹理,也不会不自动收集GC!您必须积极销毁它。
所以我要么做类似的事情
IEnumerator LoadImage()
{
// You could also use this
yield return new WaitWhile(()=>!isBrowserOpen);
while (isBrowserOpen)
{
// destroy the current texture first
if(mat.mainTexture) Destroy(mat.mainTexture);
lock (imgArray)
{
mat.mainTexture = loadTexture(imgArray);
}
yield return new WaitForSecondsRealtime(0.1f);
}
}
或者不是每次都创建新的纹理,而是简单地
private Texture2D loadTexture(byte[] imageArray, Texture2D tex)
{
lock (imageArray)
{
// Load into and overwrite the existing texture
tex.LoadImage(imageArray);
}
}
IEnumerator LoadImage()
{
// You could also use this
yield return new WaitWhile(()=>!isBrowserOpen);
// Create the texture once if it doesn't exist yet
if(!mat.mainTexture) mat.mainTexture = new Texture2D(1f, 1f);
while (isBrowserOpen)
{
lock (imgArray)
{
loadTexture(imgArray, mat.mainTexture);
}
yield return new WaitForSecondsRealtime(0.1f);
}
}
除了注释中提到的内容外,lock
imgArray
可能是一个问题,但是稍后在imgArray = screenshot.AsByteArray;
中交换该引用。在这里我不确定,但是只是为了保存起见,您应该遵循将专用对象用于锁之类的建议,例如
///<summary>
/// This is the Lock object for <see cref="imgArray" />
/// </summary>
private readonly object imgArrayLock = new object();
private Texture2D loadTexture(byte[] imageArray, Texture2D tex)
{
lock (imgArrayLock)
{
// Load into and overwrite the existing texture
tex.LoadImage(imageArray);
}
}
IEnumerator LoadImage()
{
// You could also use this
yield return new WaitWhile(()=>!isBrowserOpen);
// Create the texture once if it doesn't exist yet
if(!mat.mainTexture) mat.mainTexture = new Texture2D(1f, 1f);
while (isBrowserOpen)
{
lock (imgArrayLock)
{
loadTexture(imgArray, mat.mainTexture);
}
yield return new WaitForSecondsRealtime(0.1f);
}
}