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

Code before:
        /// </summary>
        /// <param name="disposing">true to finish writing the archive and release unmanaged and managed resources, false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing && !_isDisposed)
            {
                try
                {
                    switch (_mode)
                    {
                        case ZipArchiveMode.Read:
                            break;
                        case ZipArchiveMode.Create:
                            WriteFile();
                            break;
                        case ZipArchiveMode.Update:
                        default:
                            Debug.Assert(_mode == ZipArchiveMode.Update);
                            // Only write if the archive has been modified
                            if (IsModified)
                            {
                                WriteFile();
                            }
                            break;
                    }
                }
                finally
                {
                    CloseStreams();
                    _isDisposed = true;
                }
            }
        }

        /// <summary>
        /// Finishes writing the archive and releases all resources used by the ZipArchive object, unless the object was constructed with leaveOpen as true. Any streams from opened entries in the ZipArchive still open will throw exceptions on subsequent writes, as the underlying streams will have been closed.
        /// </summary>
        public void Dispose() => Dispose(true);

        /// <summary>
        /// Retrieves a wrapper for the file entry in the archive with the specified name. Names are compared using ordinal comparison. If there are multiple entries in the archive with the specified name, the first one found will be returned.
        /// </summary>
        /// <exception cref="ArgumentException">entryName is a zero-length string.</exception>
        /// <exception cref="ArgumentNullException">entryName is null.</exception>
        /// <exception cref="NotSupportedException">The ZipArchive does not support reading.</exception>
        /// <exception cref="ObjectDisposedException">The ZipArchive has already been closed.</exception>
        /// <exception cref="InvalidDataException">The Zip archive is corrupt and the entries cannot be retrieved.</exception>
        /// <param name="entryName">A path relative to the root of the archive, identifying the desired entry.</param>
        /// <returns>A wrapper for the file entry in the archive. If no entry in the archive exists with the specified name, null will be returned.</returns>
        public ZipArchiveEntry? GetEntry(string entryName)
        {

Review comment (performance):
In Update mode, skipping `WriteFile()` when `IsModified` is false means entries that were opened (which loads `_storedUncompressedData` into memory) may never have their internal buffers disposed/unloaded. This can retain large `MemoryStream` buffers longer than necessary (especially if callers keep references to `ZipArchiveEntry` instances after disposing the archive). Consider explicitly unloading per-entry buffers during Dispose even when you don't rewrite (e.g., iterate entries and clear/dispose cached data).

Code after:

        /// <summary>
        /// Releases the unmanaged resources used by ZipArchive and optionally finishes writing the archive and releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to finish writing the archive and release unmanaged and managed resources, false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing && !_isDisposed)
            {
                try
                {
                    switch (_mode)
                    {
                        case ZipArchiveMode.Read:
                            break;
                        case ZipArchiveMode.Create:
                            WriteFile();
                            break;
                        case ZipArchiveMode.Update:
                        default:
                            Debug.Assert(_mode == ZipArchiveMode.Update);
                            // Only write if the archive has been modified
                            if (IsModified)
                            {
                                WriteFile();
                            }
                            else
                            {
                                // Even if we didn't write, unload any entry buffers that may have been loaded
                                foreach (ZipArchiveEntry entry in _entries)
                                {
                                    entry.UnloadStreams();
                                }
                            }
                            break;
                    }
                }
                finally
                {
                    CloseStreams();
                    _isDisposed = true;
                }
            }
        }
        /// <summary>
        /// Finishes writing the archive and releases all resources used by the ZipArchive object, unless the object was constructed with leaveOpen as true. Any streams from opened entries in the ZipArchive still open will throw exceptions on subsequent writes, as the underlying streams will have been closed.
        /// </summary>
        public void Dispose() => Dispose(true);

        /// <summary>
        /// Retrieves a wrapper for the file entry in the archive with the specified name. Names are compared using ordinal comparison. If there are multiple entries in the archive with the specified name, the first one found will be returned.