gpt4 book ai didi

c# - 如何在不导致 native 内存泄漏的情况下访问图像的元数据?

转载 作者:太空狗 更新时间:2023-10-29 20:38:49 46 4
gpt4 key购买 nike

以下使用 BitmapDecoder、BitmapPropertySet 和 BitmapTypedValue 会导致 native 内存泄漏。我希望我只是错误地使用了它们……正确的使用方法是什么?他们没有实现 IDisposable,所以我不确定如何告诉他们释放他们拥有的 native 内存。

这种泄漏有可能无法避免。如果是这样,我将如何保护我的 UWP 应用免受其影响?

来自 Windows Performance Recorder/Analyzer 的 Valloc 跟踪显示许多没有取消提交时间的分配。这些对象的提交堆栈表明它们与获取元数据相关或者是元数据片段。

WPR-WPA Valloc trace of running the below test code

using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Search;

namespace Tests
{
[TestClass]
public class TestBitmapDecoderLeak
{
// Path to a folder containing jpeg's that have metadata.
private static readonly string ImageFolderPath = @"path to folder of jpegs";

// The subset of the metadata you want to get
private static readonly string [] MetadataPolicies =
{
"System.Copyright",
"System.SimpleRating",
"System.Photo.ShutterSpeed",
"System.Photo.Aperture",
"System.Photo.CameraModel",
"System.Photo.CameraManufacturer",
"System.Photo.DateTaken",
"System.Photo.ExposureTime",
"System.Photo.Flash",
"System.Photo.FlashEnergy",
"System.Photo.ISOSpeed",
"System.GPS.Longitude",
"System.GPS.Latitude"
};

[TestMethod]
public async Task RunTest()
{
// Start your profiler
Debugger.Break();

var imageFiles = await GetJpegFiles();

// Get some metadata for each image, but do nothing with it.
foreach (var imageFile in imageFiles)
{
using (var fileStream = await imageFile.OpenReadAsync())
{
var decoder = await BitmapDecoder.CreateAsync(fileStream);

var DpiX = decoder.DpiX;
var DpiY = decoder.DpiY;
var PixelSizeWidth = decoder.OrientedPixelWidth;
var PixelSizeHeight = decoder.OrientedPixelHeight;
var DecoderId = decoder.DecoderInformation.CodecId;

var properties = await decoder.BitmapProperties.GetPropertiesAsync(MetadataPolicies);

var ShutterSpeed = NullOrValType<double>(properties, "System.Photo.ShutterSpeed");
var Copyright = NullOrRefType<string>(properties, "System.Copyright");
var SimpleRating = NullOrValType<UInt16>(properties, "System.SimpleRating");
var Aperture = NullOrValType<double>(properties, "System.Photo.Aperture");
var CameraModel = NullOrRefType<string>(properties, "System.Photo.CameraModel");
var DateTaken = NullOrValType<DateTimeOffset>(properties, "System.Photo.DateTaken");
var ExposureTime = NullOrValType<double>(properties, "System.Photo.ExposureTime");
var Flash = NullOrValType<UInt16>(properties, "System.Photo.Flash");
var FlashEnergy = NullOrValType<double>(properties, "System.Photo.FlashEnergy");
var IsoSpeed = NullOrValType<UInt16>(properties, "System.Photo.ISOSpeed");
var Longitude = NullOrRefType<double[]>(properties, "System.GPS.Longitude");
var Latitude = NullOrRefType<double[]>(properties, "System.GPS.Latitude");
}
}

// Remove these so they don't add noise to the trace
imageFiles = null;

// Ensure everything is cleaned up to the best of the GC's abilities
GC.Collect();
GC.WaitForPendingFinalizers();

// Stop your profiler
Debugger.Break();
}

private static async Task<IEnumerable<StorageFile>> GetJpegFiles()
{
var folder = await StorageFolder.GetFolderFromPathAsync(ImageFolderPath);

var queryOptions = new QueryOptions
{
FolderDepth = FolderDepth.Deep,
IndexerOption = IndexerOption.DoNotUseIndexer,
};
queryOptions.FileTypeFilter.Add(".jpg");
queryOptions.FileTypeFilter.Add(".jpeg");
queryOptions.FileTypeFilter.Add(".jpe");

var folderQuery = folder.CreateFileQueryWithOptions(queryOptions);
return await folderQuery.GetFilesAsync();
}

private static T NullOrRefType<T>(IDictionary<string, BitmapTypedValue> properties, string policy)
where T : class
{
if (properties == null || !properties.ContainsKey(policy))
return null;

return (T)properties[policy].Value;
}

private static T? NullOrValType<T>(IDictionary<string, BitmapTypedValue> properties, string policy)
where T : struct
{
if (properties == null || !properties.ContainsKey(policy))
return null;

return (T)properties[policy].Value;
}
}
}

最佳答案

我不是 100% 确定这是否有助于解决内存问题,但您可以从 StorageFile 本身访问文件的属性,而无需加载到解码器中。

你会这样做:

var systemProperties = new List<string>{ "System.Photo.ShutterSpeed" };
var props = await file.Properties.RetrievePropertiesAsync(systemProperties);

这将返回一个字典,其中包含您传递的系统属性。您还可以将 null 传递给 RetrievePropertiesAsync 方法,它会返回所有属性,因此您也可以从那里进行过滤。

然后根据您希望如何使用该值,您可能会像这样从集合中提取:

if (props.ContainsKey("System.Photo.ShutterSpeed"))
{
var cameraShutterSpeedObj = props["System.Photo.ShutterSpeed"];
if (cameraShutterSpeedObj != null)
{
var cameraShutterSpeed = cameraShutterSpeedObj.ToString();
}
}

试一试,看看是否有任何改进。

关于c# - 如何在不导致 native 内存泄漏的情况下访问图像的元数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34834934/

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