Skip to content

Fixes #587: Reduce Cloudlet memory footprint - #594

Merged
manoelcampos merged 1 commit into
masterfrom
issue-587-cloudlet-memory
Oct 20, 2026
Merged

manoelcampos merged 1 commit into
masterfrom
issue-587-cloudlet-memory

Conversation

@manoelcampos

@manoelcampos manoelcampos commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #587. Builds on the Listeners helper from #586.

Changes

Part of #587 What changed Saved per Cloudlet
1. Listener sets The 3 HashSets are now immutable lists that start as the shared List.of() and change through Listeners. Notifications use for-each loops. ~192 B
2. requiredFiles Starts as List.of(); a real ArrayList is only created on the first addRequiredFile. deleteRequiredFile is now a single remove(filename) (was O(n²) on a LinkedList). setRequiredFiles copies the given list, so an immutable list no longer breaks later adds. ~32 B
3. Shared FULL model New immutable UtilizationModel.FULL (backed by UtilizationModelFullShared, whose setters do nothing), used as the default CPU model. ~24 B

Total: ~248 B per Cloudlet (~248 MB per 1M Cloudlets).

Behavior changes

  • getRequiredFiles() returns a read-only list (use addRequiredFile/deleteRequiredFile).
  • The onFinish listener list is cleared before notifying, so a listener added during the finish notification is kept for a later finish (consistent with Listener lists: lazy creation and safe changes during notification #586). Before, it was dropped.
  • Listeners.remove(list, null) returns the same list instead of throwing an NPE (List.of().indexOf(null) throws). This kept removeOnFinishListener(null) returning false, as before.
  • Setters on UtilizationModel.FULL do nothing. Users who need a configurable model can create new UtilizationModelFull().

Tests

  • mvn clean verify -Pintegration-tests: 583 tests, all passing.
  • New tests: shared UtilizationModel.FULL and its no-op setters; listener duplicates, self-removal and addition during notification; requiredFiles cases (immutable list given to the setter, delete with no files, add after deleting all files, read-only getter); Listeners.remove with null.
  • Examples CloudletListenersExample1, CreateCloudletAfterLastFinishedOne and DynamicCreationOfVmsAndCloudletsExample ran with no exceptions, with the same output as on master.

Benchmark results

Measured with MemoryFootprintBenchmark (cloudsimplus/cloudsimplus-benchmarks#10). It creates 100,000 Cloudlets and measures the heap they keep after a full GC (median of 5 rounds).

Class Before After Saved per object
CloudletSimple 464 B 216 B 248 B (−53.4%)

The measured saving matches the estimate in the table above, which splits it among the 3 changes. That's about 248 MB less heap per 1M Cloudlets.

"Before" is CloudSim Plus 8.5.1, so the difference includes all changes since that version, but it's exactly the saving estimated for this PR. Run with JDK 25.0.4 (Corretto), compressed oops, -XX:+UseSerialGC.

🤖 Generated with Claude Code

- Cloudlet listener sets are now immutable lists managed by the Listeners
  helper (#586). They start as the shared List.of(), so Cloudlets without
  listeners don't allocate 3 empty HashSets.
- requiredFiles starts as List.of() and a real list is only created on the
  first addRequiredFile. deleteRequiredFile is now O(n) instead of O(n^2).
  setRequiredFiles copies the given list, so adding files after setting an
  immutable list works. getRequiredFiles returns a read-only list.
- New immutable shared UtilizationModel.FULL, used as the default CPU
  utilization model, instead of creating a UtilizationModelFull per Cloudlet.
- Listeners.remove returns the same list when given null,
  since List.of().indexOf(null) throws NullPointerException.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@manoelcampos manoelcampos self-assigned this Oct 20, 2026
@codacy-production

codacy-production Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 21 complexity · 0 duplication

Metric Results
Complexity 21
Duplication 0

View in Codacy

🟢 Coverage 83.67% diff coverage · +0.16% coverage variation

Metric Results
Coverage variation ✅ +0.16% coverage variation
Diff coverage ✅ 83.67% diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (0813444) 9111 4630 50.82%
Head commit (06b0eab) 9136 (+25) 4657 (+27) 50.97% (+0.16%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#594) 49 41 83.67%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

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.

Reduce Cloudlet memory footprint

1 participant