>记忆足迹
我的理解是,在JVM实现中通常将一个布尔值存储为一个int.它是否正确?在这种情况下,32个标志代表了大量的内存占用量减少.
虽然JVM实现当然不尽相同,但并不总是如此.
>表演
我的理解是,cpu是非常数字驱动的,按位操作与计算中的功能一样高效.
对布尔运算使用按位运算,是否有性能损失 – 甚至增益?
>替代品
有没有更好的方式来完成同样的事情?枚举允许标志的组合,即FLAGX = FLAG1 | FLAG2?
示例代码
注意最后一个方法propogateMove()是递归的,每秒可以调用几百次,并且对应用程序的响应性有直接影响,因此使用标志来避免逻辑位和调用其他方法.
- // 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 Box 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 (Box 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 (Box 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 Box - 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 Box
- 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;
- }
解决方法
It is my understanding that commonly a boolean is stored as an int in a JVM implementation. Is this correct?
当然这取决于JVM的实现,但对主流cpu的实现可能是正确的.
In which case surely the 32 flags represent a large memory footprint reduction.
如果你在一个类中实际上有32个标志,那么该类的大量实例就是.如果你没有超过几百个例子,那就不用担心了.
It is my understanding that cpus are very number driven and bitwise operations are about as efficient as things come in computing.
这是真的.
Is there a performance penalty – or even gain – to using bitwise operations over boolean operations?
这也取决于内存使用情况.如果你只用几个对象非常集中,那么按位操作可能会减慢速度.如果你有很多对象,由于更好的缓存行为,减少的内存可能会提高性能.
Is there a better way of accomplishing the same thing? Does an Enum allow the combination of flags i.e. FLAGX = FLAG1 | FLAG2?
而不是自己做点阵操作,你可以(而且应该)使用一个BitSet
.是的,如果你可以使用Enums和一个EnumSet
,它会更清晰,但是如果你有许多枚举,由于多个EnumSet实例的开销,它可能不会产生所需的内存节省.