Windows应用商店应用中的大字节数组

时间:2013-06-27 04:09:26

标签: c# windows-8 windows-store-apps

我现在正在编写一个Windows应用商店应用阅读器,用于使用C#查看PDF文件。

目前,我正在尝试解决可能导致内存泄漏的问题。 在app中,有一种加密和解密PDF文件的方法,加密/解密方法是自定义方法,PDF文件的大小在1MB到120MB之间。

在加密和解密过程中,必须将文件作为字节数组读入内存,并处理字节以进行加密和解密。 从方法返回后,字节数组超出范围。但似乎因为它是一个大字节数组(> 85k),我认为它是在大对象堆(LOH)中声明的,并且在收集垃圾后,看起来LOH变得支离破碎。

在应用程序打开,查看和切换更多PDF文件后,内存使用率会越来越高,并且在某些时候会发生内存不足异常。

有没有办法解决大字节数组问题?或者有人遇到过这样的问题吗?

我找到了内存映射文件类,但它无法在Windows应用商店应用中使用。

我还尝试了大量字节数组(< 85k)并逐个处理文件,但在查看PDF之前加密和解密需要很长时间。

以下是代码段:
public static async Task CryptoFile(StorageFolder文件夹,字符串FileName,bool IsReaderFile)
{
        ...
    ...

byte[] fileContent = null;
buffer = await FileIO.ReadBufferAsync(file);
using (DataReader dataReader = DataReader.FromBuffer(buffer))
{
        fileContent = new byte[dataReader.UnconsumedBufferLength];
    dataReader.ReadBytes(fileContent);
}

if (fileContent == null)
        CryptResult = false;
else if (fileContent.Length == 0)
        CryptResult = false;

if (CryptResult)
{
        //Encrypt/decrypt file
    fileContent = await RecodeFile(fileContent, CryptKey, IsReaderFile);

    //Delete the original file
    file = await Folder.GetFileAsync(FileName);
    await file.DeleteAsync(StorageDeleteOption.PermanentDelete);

    //Recreate file
    file = await Folder.CreateFileAsync(FileName);
    using (IRandomAccessStream fs = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
            using (IOutputStream outStream = fs.GetOutputStreamAt(0))
        {
                using (DataWriter dataWriter = new DataWriter(outStream))
            {
                    dataWriter.WriteBytes(fileContent);
                await dataWriter.StoreAsync();
                dataWriter.DetachStream();
            }

            await outStream.FlushAsync();
        }
    }

    ....
    }

}

fileContent是用于读取整个文件内容的字节数组,当从方法返回时它将超出范围,我认为fileContent导致内存碎片,因为它的大小可能在LOH中声明。

1 个答案:

答案 0 :(得分:0)

假设您的问题与LOH相关,您考虑将较小的阵列包装成LOH友好阵列替代品。如果您愿意将块大小限制为2的幂,则可以进一步优化该示例。然后div mod变为shift和bitmask。显然,如果需要,你可以实现所有的ICollection。

我之前使用过这种方法,性能合理。

public sealed class ArrayRope<T>
{
    private readonly T[][] map;

    private readonly int blockSize;
    private readonly int noOfBlocks;

    public ArrayRope(int blockSize, int noOfBlocks)
    {
        ...
    }

    public T this[int index]
    {
        get
        {
            int ropeIndex = index / blockSize;
            int offset = index % blockSize;

            return map[ropeIndex][offset];
        }
        set
        {
            int ropeIndex = index / blockSize;
            int offset = index % blockSize;

            map[ropeIndex][offset] = value;
        }
    }

    ...
}