You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.iOS中UIImage/UIImageView内存泄漏问题修复求助

修复思路与代码优化方案

你的应用多次拖动滑块后崩溃,大概率是Core Graphics对象未正确释放引发的内存泄漏,再加上事件订阅未清理的潜在问题,下面分步骤给出具体修复方案:


1. 手动释放Core Graphics资源

在AdjustImage方法中,context.CreateCGImage返回的CGImage属于非托管资源,UIImage.FromImage不会自动释放它,每次调用都会残留内存垃圾,多次拖动后就会耗尽内存。修改这个方法:

UIImage AdjustImage(UIImage image)
{
    using (var cgImage = image.CGImage)
    using (var ciImage = CIImage.FromCGImage(cgImage))
    {
        colorCtrls.Image = ciImage;
        colorCtrls.Contrast = (float)Math.Round(sliderC.Value, 1);
        colorCtrls.Brightness = (float)Math.Round(sliderB.Value, 1);

        using (var outputImage = colorCtrls.OutputImage)
        using (var resultCGImage = context.CreateCGImage(outputImage, outputImage.Extent))
        {
            return UIImage.FromImage(resultCGImage);
        }
    }
}

补充优化:CIContext和CIColorControls都是重量级对象,建议在ViewDidLoad中一次性初始化,不用每次判断:

public override void ViewDidLoad()
{
    base.ViewDidLoad();
    // 其他初始化代码...
    context = CIContext.FromOptions(null);
    colorCtrls = new CIColorControls();
}

2. 清理图片引用,避免内存残留

在HandleValueChanged里,你只释放了resultImage,但imageView.Image的旧实例也需要释放,同时建议直接用原始的sourceImage作为调整源,避免多次叠加处理导致的画质损失和内存压力:

void HandleValueChanged(object sender, EventArgs e)
{
    // 释放旧的imageView图片资源
    imageView.Image?.Dispose();
    // 基于原始图片生成新的调整后图片
    var newImage = AdjustImage(sourceImage);
    imageView.Image = newImage;

    // 释放旧的resultImage资源
    resultImage?.Dispose();
    resultImage = newImage;
}

3. 取消事件订阅,避免ViewController内存泄漏

当ImageViewController被销毁时,滑块和按钮的事件还持有对它的引用,会导致ViewController无法被GC回收。需要在页面消失时取消所有事件订阅,同时建议把匿名委托改成单独的方法,方便取消:

public override void ViewWillDisappear(bool animated)
{
    base.ViewWillDisappear(animated);
    // 取消所有事件订阅
    sliderC.ValueChanged -= HandleValueChanged;
    sliderB.ValueChanged -= HandleValueChanged;
    resetButton.TouchUpInside -= ResetButton_TouchUpInside;
    saveButton.TouchUpInside -= SaveButton_TouchUpInside;
}

// 重置按钮事件抽成单独方法
void ResetButton_TouchUpInside(object sender, EventArgs e)
{
    sliderB.Value = 0;
    sliderC.Value = 1;
    HandleValueChanged(sender, e);
}

// 保存按钮事件抽成单独方法
void SaveButton_TouchUpInside(object sender, EventArgs e)
{
    if (resultImage != null)
    {
        ImageEditingViewController(resultImage);
    }
    else
    {
        ImageEditingViewController(sourceImage);
    }
}

4. 优化CIContext配置,减少内存占用

可以通过配置CIContextOptions来降低内存开销,比如关闭中间缓存(如果不需要的话):

context = CIContext.FromOptions(new CIContextOptions
{
    CacheIntermediates = false, // 关闭中间渲染结果缓存,减少内存使用
    UseSoftwareRenderer = false // 按需设置,硬件加速更快但内存占用略高
});

按照上面的步骤修改后,应该能解决多次拖动滑块后的内存泄漏和崩溃问题。如果仍有异常,可以用Xamarin Profiler检测内存泄漏,查看哪些对象未被正确回收。

内容的提问来源于stack exchange,提问作者Ika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:08:50