Repository: dotnet/runtime
File: src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.Async.cs (C#)

Code before:
    /// </summary>
    /// <returns>A <see cref="ValueTask"/> that represents the asynchronous dispose operation.</returns>
    public async ValueTask DisposeAsync() => await DisposeAsyncCore().ConfigureAwait(false);

    protected virtual async ValueTask DisposeAsyncCore()
    {
        if (!_isDisposed)
        {
            try
            {
                switch (_mode)
                {
                    case ZipArchiveMode.Read:
                        break;
                    case ZipArchiveMode.Create:
                        await WriteFileAsync().ConfigureAwait(false);
                        break;
                    case ZipArchiveMode.Update:
                    default:
                        Debug.Assert(_mode == ZipArchiveMode.Update);
                        // Only write if the archive has been modified
                        if (IsModified)
                        {
                            await WriteFileAsync().ConfigureAwait(false);
                        }
                        break;
                }
            }
            finally
            {
                await CloseStreamsAsync().ConfigureAwait(false);
                _isDisposed = true;
            }
        }
    }

    private async Task CloseStreamsAsync()
    {
        if (!_leaveOpen)
        {
            await _archiveStream.DisposeAsync().ConfigureAwait(false);
            if (_backingStream != null)
            {
                await _backingStream.DisposeAsync().ConfigureAwait(false);
            }
        }
        else
        {
            // if _backingStream isn't null, that means we assigned the original stream they passed
            // us to _backingStream (which they requested we leave open), and _archiveStream was
            // the temporary copy that we needed

Review comment (performance):
Async Dispose has the same resource-retention concern as sync Dispose: when `IsModified` is false, `WriteFileAsync()` is skipped and per-entry cached buffers (like `_storedUncompressedData`) may never be disposed/unloaded. Consider explicitly unloading per-entry buffers during DisposeAsync even when you don't rewrite.

Code after:
    /// Asynchronously releases the resources used by the <see cref="ZipArchive"/>.
    /// </summary>
    /// <returns>A <see cref="ValueTask"/> that represents the asynchronous dispose operation.</returns>
    public async ValueTask DisposeAsync() => await DisposeAsyncCore().ConfigureAwait(false);

    protected virtual async ValueTask DisposeAsyncCore()
    {
        if (!_isDisposed)
        {
            try
            {
                switch (_mode)
                {
                    case ZipArchiveMode.Read:
                        break;
                    case ZipArchiveMode.Create:
                        await WriteFileAsync().ConfigureAwait(false);
                        break;
                    case ZipArchiveMode.Update:
                    default:
                        Debug.Assert(_mode == ZipArchiveMode.Update);
                        // Only write if the archive has been modified
                        if (IsModified)
                        {
                            await WriteFileAsync().ConfigureAwait(false);
                        }
                        else
                        {
                            // Even if we didn't write, unload any entry buffers that may have been loaded
                            foreach (ZipArchiveEntry entry in _entries)
                            {
                                await entry.UnloadStreamsAsync().ConfigureAwait(false);
                            }
                        }
                        break;
                }
            }
            finally
            {
                await CloseStreamsAsync().ConfigureAwait(false);
                _isDisposed = true;
            }
        }
    }

    private async Task CloseStreamsAsync()
    {
        if (!_leaveOpen)
        {
            await _archiveStream.DisposeAsync().ConfigureAwait(false);
            if (_backingStream != null)