Skip to content

Conversation

@Kazanir
Copy link

@Kazanir Kazanir commented Dec 10, 2025

This pull request adds fastutil and replaces a number of standard Java Maps with type-specific implementations that avoid the autoboxing of numeric primitives into objects. This has the effect of modestly reducing the application's memory footprint in various cases, reducing the need for full-GC runs during normal operations.

@GoldenGnu
Copy link
Owner

GoldenGnu commented Dec 10, 2025

This looks very intersting! Have you profiled it to see how much faster it is and how much memory it saves?

I don't know anything about fastutil, so I will have to do a little research before I can review you PR with any confidence, so please be patient with me.

Minor issue:
New features needs the PR to be to the develop (https://github.com/GoldenGnu/jeveassets/tree/develop) branch (see https://github.com/GoldenGnu/jeveassets/blob/main/CONTRIBUTING.md).

@Bombe
Copy link

Bombe commented Dec 10, 2025

The gain from micro optimizations like these is generally pretty small, unless you’re doing thousands of operations per second. There was a time, 30 years ago, when JVMs really sucked at this kind of thing, but that’s no longer the case.

And I would like to point out that these commits have been created by Claude, which means that any contribution it makes is rather questionable in terms of copyright.

Kazanir and others added 2 commits December 10, 2025 11:31
Replaced six HashMaps with fastutil primitive collections to
eliminate autoboxing overhead in ProfileData:

Changes:
- Map<Integer, Double> transactionBuyTax → Int2DoubleOpenHashMap
- Map<Long, Double> transactionSellTax → Long2DoubleOpenHashMap
- Map<Long, Double> marketOrdersBrokersFee → Long2DoubleOpenHashMap
- Map<Integer, MarketPriceData> transactionSellPriceData → Int2ObjectOpenHashMap
- Map<Integer, MarketPriceData> transactionBuyPriceData → Int2ObjectOpenHashMap
- Map<Integer, List<MyAsset>> uniqueAssetsDuplicates → Int2ObjectOpenHashMap

Added dependency:
- it.unimi.dsi:fastutil:8.5.15 (Apache 2.0 license)

Technical details:
- Fastutil primitive maps avoid wrapper object allocation
- Used primitive get(long)/put(long, double) methods
- Added null-checking: fastutil returns 0.0 for missing keys instead of null
- Explicit primitive casts to avoid method ambiguity
- Int2ObjectOpenHashMap uses primitive int keys with object values
- No boxing/unboxing on key operations (get/put/containsKey)
- Method signature updated: createTransactionsPriceData() now uses Int2ObjectOpenHashMap

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Convert many HashMap instances with primitive keys (Long, Integer) or
primitive values (Double, Float) to fastutil primitive collections.
This eliminates autoboxing overhead which caused millions of wrapper
object allocations during data operations.

Changes across ~46 files:
- Int2ObjectOpenHashMap for Integer-keyed maps (~25 instances)
- Long2ObjectOpenHashMap for Long-keyed maps (~30 instances)
- Int2DoubleOpenHashMap for Integer->Double maps (~8 instances)
- Int2FloatOpenHashMap for Integer->Float maps (~3 instances)
- Long2LongOpenHashMap for Long->Long maps (2 instances)

Key areas converted:
- Core data structures (StaticData, Settings, ProfileData)
- ESI layer (EsiConverter, getters, manufacturing prices)
- Persistence layer (readers, writers, profile tables)
- GUI data models (MenuData, StockpileData, OutbidProcesser)

Also fixes deprecation warnings by using primitive-specific methods:
- .longValue()/.intValue() for map key access
- long2ObjectEntrySet()/int2DoubleEntrySet() for iteration
- .getLongKey()/.getIntKey() for entry key access

Test results: 81 offline tests pass, build compiles cleanly with -Werror
GC improvement: Full data update completes with 0 full GC pauses

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Kazanir
Copy link
Author

Kazanir commented Dec 11, 2025

This looks very intersting! Have you profiled it to see how much faster it is and how much memory it saves?

I don't know anything about fastutil, so I will have to do a little research before I can review you PR with any confidence, so please be patient with me.

Minor issue: New features needs the PR to be to the develop (https://github.com/GoldenGnu/jeveassets/tree/develop) branch (see https://github.com/GoldenGnu/jeveassets/blob/main/CONTRIBUTING.md).

I would say an approximate upper-bound on memory savings is 10-15% of memory from what I have seen. What is happening is that all of the places where EVE resource IDs (typically long integers) are used as keys or values in the underlying storage collections, the PR saves the overhead of generating full Java objects (i.e. Long or Int) for them. This doesn't reach into all the other places which use the traditional Java object handling for numbers in HashMaps, like the UI or the ESI library, so the total gains are in fact quite modest-seeming. In spite of that, my hope is that a smallish win will pay off in larger returns simply because these are the largest and most long-lived data structures in the application.

@Kazanir Kazanir force-pushed the optimize-primitive-collections branch from 501e4e6 to c6ba33f Compare December 12, 2025 01:53
@Kazanir Kazanir changed the base branch from main to develop December 12, 2025 01:53
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