Skip to content

[Win32] Release a region's previous area when it is refilled - #3768

Merged
HeikoKlare merged 1 commit into
eclipse-platform:masterfrom
HeikoKlare:win32-region-set-release-previous-operations
Oct 30, 2026
Merged

HeikoKlare merged 1 commit into
eclipse-platform:masterfrom
HeikoKlare:win32-region-set-release-previous-operations

Conversation

@HeikoKlare

@HeikoKlare HeikoKlare commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Problem

On Windows, GC.getClipping(Region) fills a region by appending an operation that owns a GDI region handle, but it never releases the operations describing the region's previous area, although that area is replaced.

Filling the same region repeatedly, as a paint listener with a single Region field does, therefore leaks one GDI handle per call until the region is disposed, and runs into the per-process limit of 10000 GDI objects after a few thousand paints.

Relates to #3763.

Solution

A region that is filled now releases its previous area, so its resource consumption stays constant no matter how often it is refilled.

Merge order

Depends on #3769 and should land after it. Until that fix is in, releasing the previous area while the region is still alive can pull the ground from under a region it was combined into: combining a region filled by GC.getClipping into another region and then refilling the first one makes the second one fail with a NoSuchElementException.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (win32)

  167 files  ±0    167 suites  ±0   18m 27s ⏱️ -46s
5 062 tests +1  4 976 ✅ +1   86 💤 ±0  0 ❌ ±0 
5 196 runs  +2  5 002 ✅ +1  194 💤 +1  0 ❌ ±0 

Results for commit 4bcc63d. ± Comparison against base commit dcf2e33.

♻️ This comment has been updated with latest results.

@HeikoKlare
HeikoKlare force-pushed the win32-region-set-release-previous-operations branch from 3c65e4d to b818e67 Compare October 28, 2026 11:43
@HeikoKlare
HeikoKlare requested a balanced review from Copilot October 28, 2026 12:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The lifetime change depends on unmerged PR #3769, whose reference-counting fix is absent from this snapshot, and requires Windows validation of combined-region reuse and the GDI-handle regression.

No open issues 🎉

What changed in this PR

Prevents GDI handle accumulation on Windows when GC.getClipping(Region) repeatedly replaces a region’s area. This change depends on #3769 to keep shared operations alive and must merge after it.

Changes:

  • Releases and clears operations describing the region’s previous area before storing its replacement.
  • Adds a regression test that refills one region 15,000 times and verifies its bounds.
File Description
bundles/​org.eclipse.swt/​Eclipse SWT/​win32/​org/​eclipse/​swt/​graphics/​Region.java Releases previous area operations when replacing a region’s contents.
bundles/​org.eclipse.swt/​Eclipse SWT Tests/​win32/​org/​eclipse/​swt/​graphics/​RegionWin32Tests.java Tests repeated clipping retrieval without exhausting GDI handles.

Review effort: Balanced

@HeikoKlare
HeikoKlare marked this pull request as ready for review October 28, 2026 13:01

@r-mennig r-mennig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change looks sound to me and fixes the stated resource leak. Thanks for this fix!

A Region describes its area by a list of operations that is replayed to
create a native region handle per zoom level. GC.getClipping(Region)
fills a region by appending an operation that owns one GDI region handle
per zoom, but the operations describing the region's previous area were
never released although they are replaced.

As a result, every call of GC.getClipping on a region that is filled
repeatedly retained one more operation and one more GDI region handle,
none of them freed before the region was disposed. The common idiom of a
paint listener that keeps a single Region field and fills it on every
paint therefore exhausted the per-process GDI object quota after a few
thousand paints, after which handle creation started to fail and
unrelated code ran out of handles. Replaying the ever growing operation
list also made queries like contains or getBounds progressively slower.
Such a region now only retains the operations describing its current
area, so its resource consumption stays constant no matter how often it
is refilled.

The operations are reference counted, so releasing a region's previous
area drops only that region's own reference: a snapshot taken elsewhere,
such as the copy GC.setClipping keeps, holds a reference of its own.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
@HeikoKlare
HeikoKlare force-pushed the win32-region-set-release-previous-operations branch from b818e67 to 4bcc63d Compare October 30, 2026 11:11
@HeikoKlare
HeikoKlare merged commit 9fc1c3f into eclipse-platform:master Oct 30, 2026
16 checks passed
@HeikoKlare
HeikoKlare deleted the win32-region-set-release-previous-operations branch October 30, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants