Java integer tags and bitwise operations for memory reduction
Is the use of integer tags and bitwise operations an effective way to reduce the memory footprint of large objects?
>Memory footprint
My understanding is that in JVM implementations, a Boolean value is usually stored as an int. is it correct? In this case, 32 flags represent a significant reduction in memory usage
Although JVM implementations are certainly different, they are not always the case. > perform
My understanding is that the CPU is very digitally driven, and bitwise operation is as efficient as computing
Using bitwise operations for Boolean operations, is there a performance loss – or even gain? > succedaneum
Is there a better way to do the same thing? Enumeration allows the combination of flags, i.e. flagx = flag1 | Flag2?
Sample code
Note that the last method, propogatemove (), is recursive, can be called hundreds of times per second, and has a direct impact on the responsiveness of the application. Therefore, flags are used to avoid logical bits and calling other methods
// FLAGS helper functions private final void setclear(int mask,boolean set) { if (set) set(mask); else clear(mask); } private final void set(int mask) { flags |= mask; } private final void clear(int mask) { flags &= ~mask; } private final boolean test(int mask) { return ((flags & mask) == mask); } // Flags ////////////////////////////////////////////////////////////////////// private static final boolean HORIZONTAL = true; private static final boolean VERTICAL = false; private static final int ORIENT = 0x00000001; private static final int DISPLAY = 0x00000002; private static final int HSHRINK = 0x00000004; private static final int VSHRINK = 0x00000008; private static final int SHRINK = HSHRINK | VSHRINK; private static final int TILE_IMAGE = 0x00000010; private static final int CURSOR = 0x00000020; private static final int MOUSEINSIDE = 0x00000040; private static final int MOUSEINSIDE_BLOCKED = 0x00000080; private static final int CONSTRAIN = 0x00000100; private static final int CONSTRAIN_DESCENDENT = 0x00000200; private static final int PLACE = 0x00000400; private static final int PLACE_DESCENDENT = 0x00000800; private static final int REFLOW = CONSTRAIN | CONSTRAIN_DESCENDENT | PLACE | PLACE_DESCENDENT; private static final int PACK = 0x00001000; private static final int CLIP = 0x00002000; private static final int HAS_WIDTH_SLACK = 0x00004000; private static final int HAS_HEIGHT_SLACK = 0x00008000; private static final int ALIGN_TOP = 0x00010000; private static final int ALIGN_BOTTOM = 0x00020000; private static final int ALIGN_LEFT = 0x00040000; private static final int ALIGN_RIGHT = 0x00080000; private static final int ALIGNS = ALIGN_TOP | ALIGN_BOTTOM | ALIGN_LEFT | ALIGN_RIGHT; private static final int ALIGN_TOPLEFT = ALIGN_TOP | ALIGN_LEFT; private static final int ALIGN_TOPRIGHT = ALIGN_TOP | ALIGN_RIGHT; private static final int ALIGN_BOTTOMLEFT = ALIGN_BOTTOM | ALIGN_LEFT; private static final int ALIGN_BOTTOMRIGHT = ALIGN_BOTTOM | ALIGN_RIGHT; private static final int ENTER_TRAP = 0x00100000; private static final int LEAVE_TRAP = 0x00200000; private static final int _MOVE_TRAP = 0x00400000; private static final int MOVE_TRAP = 0x00800000; private static final int CHILDREN_READ_TRAP = 0x01000000; private static final int CHILDREN_TRAP = 0x02000000; private static final int PLACE_CLEAN = 0x03000000; private static final int SHRINK_TRAP = 0x04000000; private static final int HSHRINK_TRAP = 0x10000000; private static final int VSHRINK_TRAP = 0x20000000; //private static final int UNUSED = 0x40000000; //private static final int UNUSED = 0x80000000; // Flags in switch //////////////////////////////////////////////////////////// /** get align value as a string from align flags */ private JS alignToJS() { switch(flags & ALIGNS) { case (ALIGN_TOPLEFT): return SC_align_topleft; case (ALIGN_BOTTOMLEFT): return SC_align_bottomleft; case (ALIGN_TOPRIGHT): return SC_align_topright; case (ALIGN_BOTTOMRIGHT): return SC_align_bottomright; case ALIGN_TOP: return SC_align_top; case ALIGN_BOTTOM: return SC_align_bottom; case ALIGN_LEFT: return SC_align_left; case ALIGN_RIGHT: return SC_align_right; case 0: // CENTER return SC_align_center; default: throw new Error("This should never happen; invalid alignment flags: " + (flags & ALIGNS)); } } // Flags in logic ///////////////////////////////////////////////////////////// private final boolean propagateMove(int mousex,int mousey) throws JSExn { // start with pre-event _Move which preceeds Enter/Leave if (test(_MOVE_TRAP)) { if (Interpreter.CASCADE_PREVENTED == justTriggerTraps(SC__Move,JSU.T)) { // _Move cascade prevention induces Leave propagateLeave(); // propagate cascade prevention return true; } } // REMARK: anything from here on in is a partial interruption relative // to this @R_819_2419@ so we can not call propagateLeave() directly upon it int i; boolean interrupted = false; if (!test(PACK)) { // absolute layout - allows for interruption by overlaying siblings for (@R_819_2419@ b = getChild(i=treeSize()-1); b != null; b = getChild(--i)) { if (!b.test(DISPLAY)) { continue; } if (interrupted) { b.propagateLeave(); continue; } int b_mx = mousex-getXInParent(b); int b_my = mousey-getYInParent(b); if (b.inside(b_mx,b_my)) { if (b.propagateMove(b_mx,b_my)) { interrupted = true; } } else { b.propagateLeave(); } } } else { // packed layout - interrupted still applies,plus packedhit shortcut boolean packedhit = false; for (@R_819_2419@ b = getChild(i=treeSize()-1); b != null; b = getChild(--i)) { if (!b.test(DISPLAY)) { continue; } if (packedhit) { b.propagateLeave(); continue; } int b_mx = mousex-getXInParent(b); int b_my = mousey-getYInParent(b); if (b.inside(b_mx,b_my)) { packedhit = true; if (b.propagateMove(b_mx,b_my)) { interrupted = true; } } else { b.propagateLeave(); } } } // child prevented cascade during _Move/Move which blocks // Enter on this @R_819_2419@ - invoking Leave if necessary if (interrupted) { if (test(MOUSEINSIDE)) { if (!test(MOUSEINSIDE_BLOCKED)) { // mouse prevIoUsly inside,Now blocked so invoke Leave set(MOUSEINSIDE_BLOCKED); if (test(LEAVE_TRAP)) { justTriggerTraps(SC_Leave,JSU.T); } } } else { // mouse not prevIoUsly inside,Enter not yet triggered,so // do not invoke Leave set(MOUSEINSIDE); set(MOUSEINSIDE_BLOCKED); } // propagate cascade prevention return true; } // set cursor if applicable to this @R_819_2419@ if (test(CURSOR)) { Surface s = getSurface(); if (s!=null && !s.cursorset) { s.cursor = JSU.toString(getAndTriggerTraps(SC_cursor)); s.cursorset = true; } } // fire Enter traps if (!test(MOUSEINSIDE)) { set(MOUSEINSIDE); if (test(ENTER_TRAP)) { justTriggerTraps(SC_Enter,JSU.T); } } // finish post-event Move which follows Enter/Leave if (test(MOVE_TRAP)) { if (Interpreter.CASCADE_PREVENTED == justTriggerTraps(SC_Move,JSU.T)) { // propagate cascade prevention return true; } } // propagation uninterrupted return false; }
Solution
Of course, it depends on the implementation of JVM, but the implementation of mainstream CPU may be correct
If you actually have 32 flags in a class, a large number of instances of that class are If you don't have more than a few hundred examples, don't worry
It's true.
It also depends on memory usage If you only use a few objects and are very focused, bitwise operation may slow down If you have many objects, reducing memory may improve performance due to better caching behavior
Instead of doing dot matrix operations yourself, you can (and should) use a BitSet Yes, it will be clearer if you can use enums and an enumset, but if you have many enums, it may not produce the required memory savings due to the overhead of multiple enumset instances