gpt4 book ai didi

用于减少内存的 Java 整数标志和按位运算

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:08:59 25 4
gpt4 key购买 nike

使用整数标志和按位运算是否是减少大量对象内存占用的有效方法?

  • 内存占用

    据我了解,通常 boolean 在 JVM 实现中存储为 int。这个对吗?在这种情况下,32 个标志肯定代表内存占用量大幅减少。

    当然,JVM 实现各不相同,因此情况可能并非总是如此。

  • 性能

    据我了解,CPU 非常受数字驱动,而按位运算的效率与计算中的事物一样高效。

    与 boolean 运算相比,使用按位运算是否会降低性能甚至提高性能?

  • 备选方案

    有没有更好的方法来完成同样的事情?枚举是否允许标志组合,即 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 而不是自己进行按位运算。 .是的,如果您可以使用枚举和 EnumSet,它会更干净,但是如果您有许多枚举,每个枚举都有几个元素,由于多个 EnumSet 实例的开销,它可能不会产生所需的内存节省。

关于用于减少内存的 Java 整数标志和按位运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7415590/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com