以Java格式存储颜色;字节;字节与字节[3]对比int

Dav*_*len 5 java byte

我需要存储大量的RGB颜色对象.对于一些常见的用法,这些占我应用总内存的8%到12%.我现在定义如下:

class MyColor {
byte red;
byte green;
byte blue;
}
Run Code Online (Sandbox Code Playgroud)

我假设(大多数)JVM实际上为每个条目使用int.最简单的选择是:

class MyColor {
byte [] color = new byte[3];
private static final int red = 0;
private static final int green = 1;
private static final int blue = 2;
}
Run Code Online (Sandbox Code Playgroud)

将整个数组放在一个int中吗?或者它是一个int [3]的封面?如果是第一个,这很好.如果是第二个,那么最好的是:

class MyColor {
int color;
private static final int red_shift = 0;
private static final int green_shift = 8;
private static final int blue_shift = 16;
}
Run Code Online (Sandbox Code Playgroud)

还是有更好的方法?

更新:我还将有一个getRed(),setRed(int),...作为访问器.我刚刚列出了类的数据组件以使其更小.和大小是关键的问题在这里.代码不会花费大量时间来访问这些值,因此性能不是一个大问题.

更新2:我使用SizeofUtil运行它(在下面引用 - 谢谢).我使用以下代码执行此操作:

    protected int create() {
        MyColor[] aa = new MyColor[100000];
        for (int ind=0; ind<100000; ind++)
            aa[ind] = new MyColor2();
        return 2;
    }
}.averageBytes());
Run Code Online (Sandbox Code Playgroud)

这就是它变得怪异的地方.首先,如果我不执行for循环,那么它只创建数组(所有值为null),然后它报告400016字节或4字节/数组元素.我在64位系统上,所以我很惊讶这不是800000(Java在64位O/S上有32位地址空间吗?).

但随后出现了奇怪的部分.for循环的总数是:

  • 2800016.0
  • 2600008.0
  • 2800016.0

第一个惊喜,第二种方法使用byte [3]使用更少的内存!是否有可能JVM看到声明中的字节[3]只是内联分配它?

其次,每个对象的内存是(2,800,000 - 400,000)/ 100,000 = 24.我会为第一种方法购买它,其中每个字节都是本机64位int.3*8字节= 24字节.但对于第三种情况,它是一个单一的int?这是没有意义的.

代码在这里以防我错过了一些东西:

package net.windward;

import java.util.Arrays;

public class TestSize {

    public static void main(String[] args) {

        new TestSize().runIt();
    }

    public void runIt() {
        System.out.println("The average memory used by MyColor1  is " + new SizeofUtil() {

            protected int create() {
                MyColor1[] aa = new MyColor1[100000];
                for (int ind = 0; ind < 100000; ind++)
                    aa[ind] = new MyColor1();
                return 1;
            }
        }.averageBytes());

        System.out.println("The average memory used by MyColor2  is " + new SizeofUtil() {

            protected int create() {
                MyColor2[] aa = new MyColor2[100000];
                for (int ind = 0; ind < 100000; ind++)
                    aa[ind] = new MyColor2();
                return 2;
            }
        }.averageBytes());

        System.out.println("The average memory used by MyColor3  is " + new SizeofUtil() {

            protected int create() {
                MyColor3[] aa = new MyColor3[100000];
                for (int ind = 0; ind < 100000; ind++)
                    aa[ind] = new MyColor3();
                return 1;
            }
        }.averageBytes());

        System.out.println("The average memory used by Integer[] is " + new SizeofUtil() {

            protected int create() {
                Integer[] aa = new Integer [100000];
                for (int ind = 0; ind < 100000; ind++)
                    aa[ind] = new Integer(ind);
                return 1;
            }
        }.averageBytes());

    }

    public abstract class SizeofUtil {
        public double averageBytes() {
            int runs = runs();
            double[] sizes = new double[runs];
            int retries = runs / 2;
            final Runtime runtime = Runtime.getRuntime();
            for (int i = 0; i < runs; i++) {
                Thread.yield();
                long used1 = memoryUsed(runtime);
                int number = create();
                long used2 = memoryUsed(runtime);
                double avgSize = (double) (used2 - used1) / number;
//            System.out.println(avgSize);
                if (avgSize < 0) {
                    // GC was performed.
                    i--;
                    if (retries-- < 0)
                        throw new RuntimeException("The eden space is not large enough to hold all the objects.");
                } else if (avgSize == 0) {
                    throw new RuntimeException("Object is not large enough to register, try turning off the TLAB with -XX:-UseTLAB");
                } else {
                    sizes[i] = avgSize;
                }
            }
            Arrays.sort(sizes);
            return sizes[runs / 2];
        }

        protected long memoryUsed(Runtime runtime) {
            return runtime.totalMemory() - runtime.freeMemory();
        }

        protected int runs() {
            return 11;
        }

        protected abstract int create();
    }

    class MyColor1 {
        byte red;
        byte green;
        byte blue;

        MyColor1() {
            red = green = blue = (byte) 255;
        }
    }

    class MyColor2 {
        byte[] color = new byte[3];
        private static final int red = 0;
        private static final int green = 1;
        private static final int blue = 2;

        MyColor2() {
            color[0] = color[1] = color[2] = (byte) 255;
        }
    }

    class MyColor3 {
        int color;
        private static final int red_shift = 0;
        private static final int green_shift = 8;
        private static final int blue_shift = 16;

        MyColor3() {
            color = 0xffffff;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Doo*_*nob 5

由于四个bytes 适合 an int,您可以int为您的颜色使用单个(byte如果您想稍后添加,例如 alpha ,仍然有额外的空间用于 a )。示例一小部分方法(未经测试,只是为了让您了解):

public int toIntColor(byte r, byte g, byte b) {
    int c = (int) r;
    c = (c << 8) | g;
    c = (c << 8) | b;
    return c;
}
Run Code Online (Sandbox Code Playgroud)

并取回字节:

public byte red(int c) {
    return c >> 16 & 0xFF;
}

public byte green(int c) {
    return c >> 8 & 0xFF;
}

public byte blue(int c) {
    return c & 0xFF;
}
Run Code Online (Sandbox Code Playgroud)


Boa*_*ann 0

将每种颜色作为 RGB int 存储在 int 数组中:

int[] colors;
Run Code Online (Sandbox Code Playgroud)

它非常高效而且非常方便。您还可以通过使用字节数组为每种颜色节省另一个字节 (25%),但这不太方便,而且可能不值得。

如果您使用任何类型的 MyColor 对象,则在开始存储颜色数据本身之前,您至少会在对象标头上浪费 8 个字节,在对对象的引用上浪费另外 4 个字节。

我假设(大多数)JVM 实际上对每个条目都使用 int。

不,它们是真正的字节,尽管它会占用 4 个字节的空间,而不是 3 个字节,所以它占用的空间与 int 字段相同。

byte[] color = new byte[3];是效率最低的。length数组是一个单独的对象,在计算实际数组数据之前,数组对象头至少需要 8 个额外字节,其字段需要 4 个字节,对其引用需要 4 个字节。