gpt4 book ai didi

memory-leaks - MonoTouch - WebRequest 内存泄漏和崩溃?

转载 作者:行者123 更新时间:2023-12-04 21:50:38 25 4
gpt4 key购买 nike

我有一个 MonoTouch 应用程序,它使用 3.5MB 文件执行 HTTP POST,它在我测试的主要平台上非常不稳定(带有 OS 3.1.2 的 iPhone 3G 和带有 OS 4.2.1 的 iPhone 4)。我将描述我在这里所做的事情,如果我做错了什么,也许有人可以告诉我。

为了排除我的应用程序的其余部分,我将其缩减为一个很小的示例应用程序。该应用程序是一个 iPhone OpenGL 项目,它只执行以下操作:

  • 在启动时,以 30k block 分配 6MB 内存。这模拟了我的应用程序的内存使用情况。
  • 将 3.5MB 的文件读入内存。
  • 创建一个线程来发布数据。 (创建一个 WebRequest 对象,使用 GetRequestStream(),并将 3.5MB 数据写入)。
  • 当主线程检测到posting线程完成时,转到步骤2并重复。

  • 此外,每一帧,我分配 0-100k 来模拟应用程序做某事。我没有保留对这些数据的任何引用,因此它应该被垃圾收集。

    iPhone 3G 结果:该应用程序通过 6 到 8 次上传,然后操作系统将其杀死。没有崩溃日志,但有一个 LowMemory 日志显示该应用程序已被抛弃。

    iPhone 4 结果:它在第 11 次上传时出现 Mprotect 错误。

    几个数据点:
  • 随着应用程序继续上传,仪器不会显示内存增加。
  • Instruments 没有显示任何重大泄漏(可能总共 1 KB)。
  • 无论我是用 64k block 还是一次 Stream.Write() 调用一次写入帖子数据都没有关系。
  • 在开始下一次上传之前是否等待响应(HttpWebRequest.HaveResponse)都没有关系。
  • POST 数据是否有效都没有关系。我尝试使用有效的 POST 数据,并尝试发送 3MB 的零。
  • 如果应用程序没有在每帧分配任何数据,则内存不足需要更长的时间(但如前所述,我分配每个帧的内存在分配它的帧之后没有被引用,所以它应该是被 GC 捡起)。

  • 如果没有人有任何想法,我将向 Novell 提交一个错误,但我想先看看我是否在这里做错了什么。

    如果有人想要完整的示例应用程序,我可以提供,但我已将我的 EAGLView.cs 的内容粘贴在下面。
    using System;
    using System.Net;
    using System.Threading;
    using System.Collections.Generic;
    using System.IO;
    using OpenTK.Platform.iPhoneOS;
    using MonoTouch.CoreAnimation;
    using OpenTK;
    using OpenTK.Graphics.ES11;
    using MonoTouch.Foundation;
    using MonoTouch.ObjCRuntime;
    using MonoTouch.OpenGLES;

    namespace CrashTest
    {
    public partial class EAGLView : iPhoneOSGameView
    {
    [Export("layerClass")]
    static Class LayerClass ()
    {
    return iPhoneOSGameView.GetLayerClass ();
    }

    [Export("initWithCoder:")]
    public EAGLView (NSCoder coder) : base(coder)
    {
    LayerRetainsBacking = false;
    LayerColorFormat = EAGLColorFormat.RGBA8;
    ContextRenderingApi = EAGLRenderingAPI.OpenGLES1;
    }

    protected override void ConfigureLayer (CAEAGLLayer eaglLayer)
    {
    eaglLayer.Opaque = true;
    }


    protected override void OnRenderFrame (FrameEventArgs e)
    {
    SimulateAppAllocations();
    UpdatePost();

    base.OnRenderFrame (e);
    float[] squareVertices = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
    byte[] squareColors = { 255, 255, 0, 255, 0, 255, 255, 255, 0, 0,
    0, 0, 255, 0, 255, 255 };

    MakeCurrent ();
    GL.Viewport (0, 0, Size.Width, Size.Height);

    GL.MatrixMode (All.Projection);
    GL.LoadIdentity ();
    GL.Ortho (-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
    GL.MatrixMode (All.Modelview);
    GL.Rotate (3.0f, 0.0f, 0.0f, 1.0f);

    GL.ClearColor (0.5f, 0.5f, 0.5f, 1.0f);
    GL.Clear ((uint)All.ColorBufferBit);

    GL.VertexPointer (2, All.Float, 0, squareVertices);
    GL.EnableClientState (All.VertexArray);
    GL.ColorPointer (4, All.UnsignedByte, 0, squareColors);
    GL.EnableClientState (All.ColorArray);

    GL.DrawArrays (All.TriangleStrip, 0, 4);

    SwapBuffers ();
    }


    AsyncHttpPost m_Post;
    int m_nPosts = 1;

    byte[] LoadPostData()
    {
    // Just return 3MB of zeros. It doesn't matter whether this is valid POST data or not.
    return new byte[1024 * 1024 * 3];
    }

    void UpdatePost()
    {
    if ( m_Post == null || m_Post.PostStatus != AsyncHttpPostStatus.InProgress )
    {
    System.Console.WriteLine( string.Format( "Starting post {0}", m_nPosts++ ) );

    byte [] postData = LoadPostData();

    m_Post = new AsyncHttpPost(
    "https://api-video.facebook.com/restserver.php",
    "multipart/form-data; boundary=" + "8cdbcdf18ab6640",
    postData );
    }
    }

    Random m_Random = new Random(0);
    List< byte [] > m_Allocations;

    List< byte[] > m_InitialAllocations;

    void SimulateAppAllocations()
    {
    // First time through, allocate a bunch of data that the app would allocate.
    if ( m_InitialAllocations == null )
    {
    m_InitialAllocations = new List<byte[]>();
    int nInitialBytes = 6 * 1024 * 1024;
    int nBlockSize = 30000;
    for ( int nCurBytes = 0; nCurBytes < nInitialBytes; nCurBytes += nBlockSize )
    {
    m_InitialAllocations.Add( new byte[nBlockSize] );
    }
    }

    m_Allocations = new List<byte[]>();
    for ( int i=0; i < 10; i++ )
    {
    int nAllocationSize = m_Random.Next( 10000 ) + 10;
    m_Allocations.Add( new byte[nAllocationSize] );
    }
    }
    }




    public enum AsyncHttpPostStatus
    {
    InProgress,
    Success,
    Fail
    }

    public class AsyncHttpPost
    {
    public AsyncHttpPost( string sURL, string sContentType, byte [] postData )
    {
    m_PostData = postData;
    m_PostStatus = AsyncHttpPostStatus.InProgress;
    m_sContentType = sContentType;
    m_sURL = sURL;

    //UploadThread();
    m_UploadThread = new Thread( new ThreadStart( UploadThread ) );
    m_UploadThread.Start();
    }

    void UploadThread()
    {
    using ( MonoTouch.Foundation.NSAutoreleasePool pool = new MonoTouch.Foundation.NSAutoreleasePool() )
    {
    try
    {
    HttpWebRequest request = WebRequest.Create( m_sURL ) as HttpWebRequest;
    request.Method = "POST";
    request.ContentType = m_sContentType;
    request.ContentLength = m_PostData.Length;

    // Write the post data.
    using ( Stream stream = request.GetRequestStream() )
    {
    stream.Write( m_PostData, 0, m_PostData.Length );
    stream.Close();
    }

    System.Console.WriteLine( "Finished!" );

    // We're done with the data now. Let it be garbage collected.
    m_PostData = null;

    // Finished!
    m_PostStatus = AsyncHttpPostStatus.Success;
    }
    catch ( System.Exception e )
    {
    System.Console.WriteLine( "Error in AsyncHttpPost.UploadThread:\n" + e.Message );
    m_PostStatus = AsyncHttpPostStatus.Fail;
    }
    }
    }

    public AsyncHttpPostStatus PostStatus
    {
    get
    {
    return m_PostStatus;
    }
    }


    Thread m_UploadThread;

    // Queued to be handled in the main thread.
    byte [] m_PostData;

    AsyncHttpPostStatus m_PostStatus;
    string m_sContentType;
    string m_sURL;
    }
    }

    最佳答案

    我认为您应该一次读取 1 KB(或任意大小)的文件并将其写入 Web 请求。

    与此类似的代码:

    byte[] buffer = new buffer[1024];
    int bytesRead = 0;
    using (FileStream fileStream = File.OpenRead("YourFile.txt"))
    {
    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
    {
    httpPostStream.Write(buffer, 0, bytesRead);
    }
    }

    这不是我的想法,但我认为这是正确的。

    这样,当您真的不需要时,您就不会在内存中 float 额外的 3MB。我认为这样的技巧在 iDevices(或其他设备)上比在桌面上更重要。

    还要测试缓冲区的大小,更大的缓冲区会让你在一定程度上获得更好的速度(我记得 8KB 相当不错)。

    关于memory-leaks - MonoTouch - WebRequest 内存泄漏和崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5492469/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com