Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@mkeskells
Copy link
Contributor

@mkeskells mkeskells commented Aug 31, 2025

SUMMARY

Simlify and streamline the access to a Container, having it held directtly by a LeafNode, rather than a reference to the container in another structure
This also removes the inherent unbounded memory leaks in HighLowContainer, and the retained memory (EDIT example in the comments)
It speed up access, by removing a layer if indirection on access to most operation (Foreach is probably the only operation that isnt faster, and may be slightly slower)

As serialisation was bound to this structure there was a rewrite of the serialisation & deserialisation structure and code
The format of the serialised form changes (its smaller)
The serialised form address a version number, and old formats wit fail with a message to indicate the format isnt correct. This also allows for future version aif format changes again

For the Serialisation and deserialisation The code was moved closer to the abstraction being handled, except for the cases of the Containers. I didnt want to chnage the scope of this PR to change the 32 bit structure and code
I think that some code duplication could be removed in a followup as the DataInput/DataOutput and ByteBuffer code are similar, and could be unified, howerev that would IMO be too much for the scop of this PR

EDIT
Benchmarks and raw results are inclded now as a comment

I have added test for the serialisation format

Automated Checks

  • I have run ./gradlew test and made sure that my PR does not break any unit test.

At this is a larger PR I have structure then commits the allow review of some of the enabling chnages prior to the bulk of the change. Each commit was initially tested against the unit tests in the project

@lemire
Copy link
Member

lemire commented Sep 1, 2025

This is a massive PR. Difficult to review.

Before doing anything of the sort, please make sure you have good benchmark results. Changing thousands of lines of code is not something that should be done lightly.

@mkeskells
Copy link
Contributor Author

This is a massive PR. Difficult to review.

Thats why I structured the commits to enable to review in bits. The first 5 commits are easy to review small enablers, but removing a data structure in the middle of the implementation had knock on effects. THe 6th commit is bit though

Before doing anything of the sort, please make sure you have good benchmark results. Changing thousands of lines of code is not something that should be done lightly.

I did try to discuss this as a design issue, but all I go was "you need benchmarks". No design discussion

As I said in the summary I will add benchmarks shortly. Benchmarks don't run on code concept, they require an implementation. I offered to benchmark a slice but that was rejected

@lemire
Copy link
Member

lemire commented Sep 1, 2025

@mkeskells You need to sync with the main branch.

@blacelle @richardstartin and others: would you chime in ?

I did try to discuss this as a design issue, but all I go was "you need benchmarks". No design discussion

I have a general bias against far reaching pull requests. My bias is not unusual nor is it controversial. Please read again what I wrote: This is a massive PR. Difficult to review. Before doing anything of the sort, please make sure you have good benchmark results. Changing thousands of lines of code is not something that should be done lightly.

Let us go back to how you justify it: It speed up access, by removing a layer if indirection on access to most operation
and then This also removes the inherent unbounded memory leak.

These are two objective and important statements. I am asking you to document and justify these claims.

@mkeskells mkeskells marked this pull request as draft September 2, 2025 06:18
@mkeskells
Copy link
Contributor Author

MArking as Draft as I will not have time on this PR - to sync up, tidy up or benchmark for at least this week

@mkeskells
Copy link
Contributor Author

The majority of the new code, other than tests is for the change to the serialisation format (I think. Haven't counted then though)

That change is required by this PR but could be implemented against the current main branch. Its not seperate entirely, but mostly

Thus would make the serialized form smaller, and less tied to the internal memory structure than the current serialised form. The change is largely orthogonal, but dependent

It would also make the serialised form deterministic based on the content, which it isn't currently, as the memory leaks in Containers are reflected in the serialised form, and dehydrated form

The numbers are easier to review as well (serialised size, time, garbage). Retained size should be unaffected

@blacelle
Copy link
Member

blacelle commented Sep 2, 2025

Changing the serialization format certainly adds friction to this PR. Do you confirm this PR does break binary compatibility ? Or does it change the binary output because of the optimizations, while keeping compatibility?

#598 refers to some matters around Roaring64 serialization format. (It is mostly focused on Map-based, but it refers to ART ones too).

@mkeskells
Copy link
Contributor Author

mkeskells commented Sep 2, 2025

Changing the serialization format certainly adds friction to this PR. Do you confirm this PR does break binary compatibility ? Or does it change the binary output because of the optimizations, while keeping compatibility?
Sorry if I was not clear. The PR requires that the serialisation format is changed, as the current format contains the data structures that are removed

The new, or another format that just serialised the required data could be made. I haven't looked at the NavigableMap based format, but will have a look

The format that I proposed here (but am not too fussed about) retains the Trie structure, and therefore is implementation dependent, cos we could change the tree. It doesn't contain the internal fields of the implementing, so just the node with prefix, and count of children, and key/child array

#598 refers to some matters around Roaring64 serialization format. (It is mostly focused on Map-based, but it refers to ART ones too).

Will have a look ... when i can.
I had a look. It seems from a quick read that the proposal is that we write a sequence of 32bit high vae -> 32bit roaringBitmap. Thats quite a way away from the structure of the 64BitRoaringMap, bit not unachievable. It would churn memory a bit as I seet if, converting the lower 2 bytes of the Trie into a data structure, or at least some scanning to work out number of entries etc
Am I reading that correctly.
as Seq<32bit int, Seq<32bit roaringMap>>
which I think is Seq<32bit int, Seq<16 bit int, 16bit container>

I would imagine that having a portable format would be useful, but also a fast format has some attractions. Its not black and white. Maybe there is a need for both.
Certainly if we were to do this I would like to get rid of the duplication of strucure with DataOutput and ByteBuffer!

Is there a specific view if what the format should be?

@mkeskells
Copy link
Contributor Author

copied the serialisation format to #805
I havent checked it, but it passes tests. Probably some dead code there still

WIll check it in more details later, but sharing for the conversation, but its very draft

@mkeskells
Copy link
Contributor Author

Let us go back to how you justify it: It speed up access, by removing a layer if indirection on access to most operation and then This also removes the inherent unbounded memory leak.

These are two objective and important statements. I am asking you to document and justify these claims.

Sorry I thought this was obvious. I have mentioned this memory leak many times in our conversations, and I presume this was well know and accepted. Every time that a LafNode is removed (e.g. empty) the Containers null the reference bu doesnt recliam or reuse that slot
Trim doesnt combact this either (I was writing a beter trip when I realised that the whole HighLow structure in Roaring64 doesnt add anything (unlike the HighLow in the 32 bit implementation which is a wrapper around parellel arrays)
Serilisation doesnt free the slot either

In terms of the access, it can be seem that most operation that need to do any bitmap operation operation traverses the graph of obects Roaring64Bitmap -> HighLowContainer -> Art -> Node .... LeafNode -> [then to access the container] highLowContainer -> Containers -> array -> Container

This can be shortned to Roaring64Bitmap -> Art -> Node .... LeafNode -> Container
Probably could remove Art as well eventualy, but the bigest traversal difference in the containers/highlow

@blacelle blacelle mentioned this pull request Sep 8, 2025
1 task
@lemire
Copy link
Member

lemire commented Sep 9, 2025

Every time that a LafNode is removed (e.g. empty) the Containers null the reference bu doesnt recliam or reuse that slot

I do not consider this a memory leak.

If we were to consider that it is a memory leak, then you'd have to consider the standard HashMap in Java to be plagued by memory leaks. The HashMap implementation does not include any mechanism to reduce the capacity of the table when keys are removed. The resize() method is designed to either initialize the table or increase its size (typically doubling it). There is no code path that creates a smaller table when the number of entries decreases.

This does not mean that the current design cannot be improved, of course.

In terms of the access, it can be seem that most operation that need to do any bitmap operation operation traverses the (...)

I get that your claim is that you can remove an indirection and thus improve the performance. However, if that is your claim, then you should be able to support it with benchmark results.

@mkeskells
Copy link
Contributor Author

I do not consider this a memory leak.

If we were to consider that it is a memory leak, then you'd have to consider the standard HashMap in Java to be plagued by memory leaks. The HashMap implementation does not include any mechanism to reduce the capacity of the table when keys are removed. The resize() method is designed to either initialize the table or increase its size (typically doubling it). There is no code path that creates a smaller table when the number of entries decreases.

IMHO You have a very narrow definition of a memory leak, lets look a a "accepted" definition of a memory leak - https://en.wikipedia.org/wiki/Memory_leak

"In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in a way that memory which is no longer needed is not released"

That pretty much exactly match the situation described.
It inappropriate to say this isn't a memory leak because some other implementation has the same characteristic. By that definition there are no memory leak in software, because there are similar bugs elsewhere. - And yes HashMap, HashSet have memory leaks. No-one said they didn't until now

Its also not an equivalent comparison. Repeated addition and removal for HashMap doesn't grow memory use (it caps it to the maximum size). Repeated additional and removal for this structure leak more memory. Serialisation and deserialization clean the memory for a HashMap, it doesn't for this structure.

In terms of the access, it can be seem that most operation that need to do any bitmap operation operation traverses the (...)

I get that your claim is that you can remove an indirection and thus improve the performance. However, if that is your claim, then you should be able to support it with benchmark results.

As I said in my initial post, and subsequently, I will provide benchmarks (I agree this is more that a few days), when I have time, and access to a machine which is stable. Laptops are not suitable for CPU comparison due to thermal management and other issues, and this is not my day job, Its not a focus as this is not a library that I will be using as I have a smaller faster closed source direct mapped implementation that meets my much narrower needs

@blacelle
Copy link
Member

Its also not an equivalent comparison. Repeated addition and removal for HashMap doesn't grow memory use (it caps it to the maximum size). Repeated additional and removal for this structure leak more memory. Serialisation and deserialization clean the memory for a HashMap, it doesn't for this structure.

I did not analyzed the potential memory-leak. @mkeskells Could you provide a unit-test demonstrating the issue, so we can agree current behavior is acceptable or not (independantly of any design analysis). (Similarly to benchmarks on the performance aspect, we're just expecting factual elements before moving forwards on such evolutions). Such a unit-test would also prevent future regressions (standard software practise).

@mkeskells
Copy link
Contributor Author

I did not analyzed the potential memory-leak. @mkeskells Could you provide a unit-test demonstrating the issue, so we can agree current behavior is acceptable or not

I can provide a example. Not a unit test (as there isnt a pass/fail) but some code that demmonstrates one of the causes

@blacelle
Copy link
Member

Anything reproducing the behavior would be useful. Thanks

@mkeskells
Copy link
Contributor Author

Some performance results

Some of the results are a little out of step so some more digging may be needed (e.g. addEachMising(10k, 10k, true) but generally positive

For each case ther eis a summary, csv, and full text in the gists below
command line to run this was
java -Xms8g -Xmx8g -jar benchmarks.jar -rf csv -rff data.csv -o run.txt -prof gc -bm avgt -tu ns -w 5 -wf 0 -wi 2 -i 5 -f 1 -r 5 -jvmArgs -Xmx8g 'org.roaringbitmap.longlong.(AddRoaring64|BuildFromEmpty).*'

as a comparison of the effect of the PR

Processed test Benchmark Before ns/op After ns/op ns/op Improvement % Before B/op After B/op B/op Improvement % "Param: addedSize" "Param: initialSize" "Param: ordered" "Param: orderedAdd" "Param: size"
AddRoaring64.AddExistingState.addEachMissing 246306.14 218587.69 11.25% 480150.58 480145.91 0.00% 10000 10000 true null
AddRoaring64.AddExistingState.addEachMissing 327161.68 289453.30 11.53% 480149.13 480151.37 -0.00% 10000 10000 false null
AddRoaring64.AddExistingState.addEachMissing 449354.63 439665.99 2.16% 740906.61 500902.82 32.39% 10000 100000 true null
AddRoaring64.AddExistingState.addEachMissing 586318.53 561191.55 4.29% 740921.73 500899.41 32.40% 10000 100000 false null
AddRoaring64.AddExistingState.addEachMissing 623784.24 554419.38 11.12% 911296.60 671267.17 26.34% 10000 1000000 true null
AddRoaring64.AddExistingState.addEachMissing 844258.66 803991.49 4.77% 911297.02 671269.62 26.34% 10000 1000000 false null
AddRoaring64.AddExistingState.addEachMissing 4089779.61 3953641.76 3.33% 8053553.98 5653425.79 29.80% 100000 100000 true null
AddRoaring64.AddExistingState.addEachMissing 7975417.62 8905346.41 -11.66% 8053624.99 5653556.22 29.80% 100000 100000 false null
AddRoaring64.AddExistingState.addEachMissing 7550767.91 8509514.74 -12.70% 8690335.00 6290070.32 27.62% 100000 1000000 true null
AddRoaring64.AddExistingState.addEachMissing 15012830.28 13563218.89 9.66% 6290197.98 6290246.14 -0.00% 100000 1000000 false null
AddRoaring64.AddExistingState.addEachMissing 34164988.83 32939885.66 3.59% 72098828.21 48097773.87 33.29% 1000000 1000000 true null
AddRoaring64.AddExistingState.addEachMissing 221387773.04 188717651.95 14.76% 72098679.79 48098484.33 33.29% 1000000 1000000 false null
AddRoaring64.AddExistingState.addEachExisting 224328.62 186878.59 16.69% 480030.11 480025.24 0.00% 10000 10000 true null
AddRoaring64.AddExistingState.addEachExisting 241559.21 187776.18 22.26% 720034.91 480025.15 33.33% 10000 10000 false null
AddRoaring64.AddExistingState.addEachExisting 659799.10 550824.94 16.52% 737109.92 497108.89 32.56% 10000 100000 true null
AddRoaring64.AddExistingState.addEachExisting 486578.56 451438.45 7.22% 737112.65 497101.63 32.56% 10000 100000 false null
AddRoaring64.AddExistingState.addEachExisting 1046140.46 774216.14 25.99% 913843.24 673831.02 26.26% 10000 1000000 true null
AddRoaring64.AddExistingState.addEachExisting 927899.99 630788.07 32.02% 913820.92 673833.96 26.26% 10000 1000000 false null
AddRoaring64.AddExistingState.addEachExisting 3234650.25 2717082.56 16.00% 7363525.49 4963485.17 32.59% 100000 100000 true null
AddRoaring64.AddExistingState.addEachExisting 3098781.22 2922285.67 5.70% 7363516.96 4963495.10 32.59% 100000 100000 false null
AddRoaring64.AddExistingState.addEachExisting 22923082.06 13481613.27 41.19% 9165507.91 6765399.06 26.19% 100000 1000000 true null
AddRoaring64.AddExistingState.addEachExisting 10954279.87 9570008.35 12.64% 9165487.61 6765384.82 26.19% 100000 1000000 false null
AddRoaring64.AddExistingState.addEachExisting 32409077.62 29052633.58 10.36% 91742191.38 67742283.27 26.16% 1000000 1000000 true null
AddRoaring64.AddExistingState.addEachExisting 51192956.44 28244198.81 44.83% 91742472.98 67742376.11 26.16% 1000000 1000000 false null
BuildFromEmpty.addArray 429971.13 393397.16 8.51% 2039031.66 1812805.86 11.09% true 10000
BuildFromEmpty.addArray 4760917.81 4231154.04 11.13% 19019358.65 16559612.72 12.93% true 100000
BuildFromEmpty.addArray 101047783.47 56842223.89 43.75% 248648454.38 228021112.02 8.30% true 1000000
BuildFromEmpty.addArray 613915.52 531822.28 13.37% 1990591.03 1649216.51 17.15% false 10000
BuildFromEmpty.addArray 7111641.90 6533603.29 8.13% 18418475.72 15958655.92 13.36% false 100000
BuildFromEmpty.addArray 224796575.97 185268155.85 17.58% 241264957.25 220656027.17 8.54% false 1000000
BuildFromEmpty.addLong 438359.20 402378.71 8.21% 2039034.37 1812804.34 11.09% true 10000
BuildFromEmpty.addLong 4957878.38 4256919.05 14.14% 19019441.61 16559719.45 12.93% true 100000
BuildFromEmpty.addLong 111175195.83 56151590.77 49.49% 248628259.67 228021822.05 8.29% true 1000000
BuildFromEmpty.addLong 595854.20 571796.09 4.04% 1875447.29 1764359.54 5.92% false 10000
BuildFromEmpty.addLong 7503121.44 6538367.91 12.86% 18418488.95 15843400.84 13.98% false 100000
BuildFromEmpty.addLong 258095497.93 182663519.29 29.23% 241271521.16 220655463.71 8.54% false 1000000
AddRoaring64.AddExistingState.addAllExisting 219266.96 193488.67 11.76% 480030.02 480029.12 0.00% 10000 10000 true null
AddRoaring64.AddExistingState.addAllExisting 213003.58 192057.66 9.83% 480029.94 480029.55 0.00% 10000 10000 false null
AddRoaring64.AddExistingState.addAllExisting 672467.13 578040.60 14.04% 737109.52 497108.83 32.56% 10000 100000 true null
AddRoaring64.AddExistingState.addAllExisting 490562.72 455359.04 7.18% 737106.77 497095.28 32.56% 10000 100000 false null
AddRoaring64.AddExistingState.addAllExisting 1065231.26 817637.95 23.24% 913839.32 673831.04 26.26% 10000 1000000 true null
AddRoaring64.AddExistingState.addAllExisting 807904.90 609913.82 24.51% 913840.19 673831.64 26.26% 10000 1000000 false null
AddRoaring64.AddExistingState.addAllExisting 3170662.27 2987445.08 5.78% 7363527.22 4963496.65 32.59% 100000 100000 true null
AddRoaring64.AddExistingState.addAllExisting 3258836.37 2810439.44 13.76% 7363617.52 4963486.03 32.59% 100000 100000 false null
AddRoaring64.AddExistingState.addAllExisting 27716299.66 14574538.92 47.42% 9165476.86 6765379.91 26.19% 100000 1000000 true null
AddRoaring64.AddExistingState.addAllExisting 11826457.28 10057459.47 14.96% 9165482.32 6765390.39 26.19% 100000 1000000 false null
AddRoaring64.AddExistingState.addAllExisting 31120388.20 28224949.19 9.30% 91742913.53 67742208.49 26.16% 1000000 1000000 true null
AddRoaring64.AddExistingState.addAllExisting 33059172.80 29167283.70 11.77% 91742024.12 67742261.97 26.16% 1000000 1000000 false null
BuildFromEmpty.bitmapOf 434215.99 393692.10 9.33% 2039034.05 1812802.66 11.10% true 10000
BuildFromEmpty.bitmapOf 4731512.70 4225573.00 10.69% 19019363.42 16559540.65 12.93% true 100000
BuildFromEmpty.bitmapOf 101262347.39 56466330.58 44.24% 248651371.34 228020915.36 8.30% true 1000000
BuildFromEmpty.bitmapOf 605157.05 538066.02 11.09% 1990588.79 1649219.33 17.15% false 10000
BuildFromEmpty.bitmapOf 7009736.59 6567152.02 6.31% 18418484.60 15958641.48 13.36% false 100000
BuildFromEmpty.bitmapOf 228835391.94 183369470.82 19.87% 241280996.70 220655467.58 8.55% false 1000000
AddRoaring64.AddExistingState.addAllMissing 272900.43 221176.89 18.95% 480150.78 480150.10 0.00% 10000 10000 true null
AddRoaring64.AddExistingState.addAllMissing 322706.00 305566.74 5.31% 480149.35 480151.65 -0.00% 10000 10000 false null
AddRoaring64.AddExistingState.addAllMissing 453929.22 463409.77 -2.09% 740908.52 500892.07 32.39% 10000 100000 true null
AddRoaring64.AddExistingState.addAllMissing 588933.40 559784.76 4.95% 740923.03 500901.77 32.39% 10000 100000 false null
AddRoaring64.AddExistingState.addAllMissing 627616.30 597100.81 4.86% 911296.79 671293.31 26.34% 10000 1000000 true null
AddRoaring64.AddExistingState.addAllMissing 791749.77 763087.96 3.62% 911298.40 671314.51 26.33% 10000 1000000 false null
AddRoaring64.AddExistingState.addAllMissing 4056982.58 3871758.36 4.57% 8053465.69 5653461.11 29.80% 100000 100000 true null
AddRoaring64.AddExistingState.addAllMissing 8038347.21 8972955.60 -11.63% 8053731.81 5653676.18 29.80% 100000 100000 false null
AddRoaring64.AddExistingState.addAllMissing 7617061.74 7742544.75 -1.65% 8690343.62 6290107.66 27.62% 100000 1000000 true null
AddRoaring64.AddExistingState.addAllMissing 15801676.20 13874218.85 12.20% 8690293.76 6290063.54 27.62% 100000 1000000 false null
AddRoaring64.AddExistingState.addAllMissing 35405575.72 33222563.61 6.17% 72097214.19 48097876.10 33.29% 1000000 1000000 true null
AddRoaring64.AddExistingState.addAllMissing 216193426.67 162357213.55 24.90% 72097702.14 48098116.01 33.29% 1000000 1000000 false null

@mkeskells
Copy link
Contributor Author

Anything reproducing the behavior would be useful. Thanks

Here is a simple example where a bitmap containing one bit consumes all heap

import org.roaringbitmap.art.Containers;
import org.roaringbitmap.longlong.HighLowContainer;
import org.roaringbitmap.longlong.Roaring64Bitmap;

import java.lang.reflect.Field;

public class HighLowMemory {
    public static void main(String[] args) throws Exception {
        new HighLowMemory().run();
    }
    private final Field highLow;
    private final Field containers;
    private final Field containers_containerSize;
    private final Field containers_firstLevelIndex;
    private final Field containers_secondLevelIndex;
    HighLowMemory() throws Exception {
        highLow = Roaring64Bitmap.class.getDeclaredField("highLowContainer");
        highLow.setAccessible(true);

        containers = HighLowContainer.class.getDeclaredField("containers");
        containers.setAccessible(true);

        containers_containerSize = Containers.class.getDeclaredField("containerSize");
        containers_containerSize.setAccessible(true);

        containers_firstLevelIndex = Containers.class.getDeclaredField("firstLevelIdx");
        containers_firstLevelIndex.setAccessible(true);

        containers_secondLevelIndex = Containers.class.getDeclaredField("secondLevelIdx");
        containers_secondLevelIndex.setAccessible(true);
    }
    public void run() throws Exception {
        int count = 10000;
        Roaring64Bitmap rb = new Roaring64Bitmap();
        for (long i = 0; i < 100; i++) {
            for (long j = 0; j < 10000000; j++) {
                rb.add(j << 16);
                rb.remove((j - 1) << 16);
            }
            System.out.println("After cycle " + i + " size: " + rb.getLongCardinality());
            System.out.println("slots used " + getSlotsUsed(rb));
        }
    }

    private String getSlotsUsed(Roaring64Bitmap rb) throws Exception {
        Containers container  = (Containers)containers.get(highLow.get(rb));
        return "containerSize=" + containers_containerSize.getLong(container) +
                ", firstLevelIdx=" + containers_firstLevelIndex.getInt(container) +
                ", secondLevelIdx=" + containers_secondLevelIndex.getInt(container);
    }
}

produces

After cycle 0 size: 1
slots used containerSize=1, firstLevelIdx=0, secondLevelIdx=9999999
After cycle 1 size: 1
slots used containerSize=1, firstLevelIdx=0, secondLevelIdx=19999998
After cycle 2 size: 1
slots used containerSize=1, firstLevelIdx=0, secondLevelIdx=29999997
After cycle 3 size: 1

...

slots used containerSize=1, firstLevelIdx=0, secondLevelIdx=439999956
After cycle 44 size: 1
slots used containerSize=1, firstLevelIdx=0, secondLevelIdx=449999955
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.base/java.lang.reflect.Array.newArray(Native Method)
	at java.base/java.lang.reflect.Array.newInstance(Array.java:78)
	at java.base/java.util.Arrays.copyOf(Arrays.java:3721)
	at java.base/java.util.Arrays.copyOf(Arrays.java:3689)
	at org.roaringbitmap.art.Containers.grow(Containers.java:184)
	at org.roaringbitmap.art.Containers.addContainer(Containers.java:107)
	at org.roaringbitmap.longlong.HighLowContainer.put(HighLowContainer.java:78)
	at org.roaringbitmap.longlong.Roaring64Bitmap.addLong(Roaring64Bitmap.java:67)
	at org.roaringbitmap.longlong.Roaring64Bitmap.add(Roaring64Bitmap.java:1028)
	at HighLowMemory.run(HighLowMemory.java:37)
	at HighLowMemory.main(HighLowMemory.java:9)

@mkeskells
Copy link
Contributor Author

Some of the results are a little out of step so some more digging may be needed (e.g. addEachMising(10k, 10k, true) but generally positive

After looking at the inconsistent results, it seems that approx 1 time in 20 to one of the benchmarks seems out of line with the norm. I expect the JIT made a different choice that was good/bad.
The difference doesn't seem to be related to the actual parameters for the performance test, just a different fork

@mkeskells
Copy link
Contributor Author

Anything reproducing the behavior would be useful. Thanks

Here is a simple example where a bitmap containing one bit consumes all heap

Did anyone have a chance to look at this?

1 + //runOptimized
4 + //bitDepth
this.ebM.serializedSizeInBytes();
if (size <= Integer.MAX_VALUE) {
Copy link
Member

Choose a reason for hiding this comment

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

You may want to also rule out the case where size becomes negative.

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