用Java存储颜色-byte; byte; byte vs. byte [3] vs int [英] Store a color in Java - byte;byte;byte vs. byte[3] vs int

查看:70
本文介绍了用Java存储颜色-byte; byte; byte vs. byte [3] vs int的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要存储大量RGB颜色对象。这些占了8%&某些常见用法,占应用总内存的12%。我目前对它的定义如下:

I need to store a ton of RGB color objects. These are taking up between 8% & 12% of the total memory of my app for some common usages. I presently have it defined as follows:

class MyColor {
byte red;
byte green;
byte blue;
}

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

I assume that (most) JVMs actually use an int for each of those entries. The easiest alternative is:

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;
}

将整个数组放在单个int吗?还是它是一个int [3]?如果是第一个,那就太好了。如果是第二个,那么最好的方法是:

Will that put the entire array in a single int? Or is it an int[3] under the covers? If the first, this is great. If the second, then the best is:

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;
}

还是有更好的方法?

更新::我还将有一个getRed(),setRed(int),...作为访问器。我只是列出了该类的数据组件以使其更小。而大小是这里的关键问题。代码不需要花费很多时间来访问这些值,因此性能并不是一个大问题。

Update: I will also have a getRed(), setRed(int), ... as the accessors. I just listed the data components of the class to keep it smaller. And size is the critical issue here. The code doesn't spend a lot of time accessing these values so performance is not a big issue.

更新2:使用 SizeofUtil (下面引用-谢谢)。我使用以下代码进行了此操作:

Update 2: I went and ran this using SizeofUtil (referenced below - thank you). I did this using code as follows:

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

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

And here's where it gets weird. First, if I don't do the for loop, so it only is creating the array (with all values null), then it reports 400016 bytes or 4 bytes/array element. I'm on a 64-bit system so I'm surprised this isn't 800000 (does Java have a 32-bit address space on a 64-bit O/S?).

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

But then came the weird part. The total numbers with the for loop are:


  • 2800016.0

  • 2600008.0

  • 2800016.0

第一个惊喜,第二种使用byte [3]的方法使用的内存更少!

First surprise, the 2nd approach with byte[3] uses less memory! Is it possible that the JVM, seeing the byte[3] in the declaration, just allocates it inline?

第二,每个对象的内存为(2,800,000-400,000)/ 100,000 =24。对于第一种方法,我将购买该方法,其中每个字节都由一个本机64位int组成。 3 * 8字节= 24字节。但是对于第三种情况,它是单个整数?

Second, the memory per object is (2,800,000 - 400,000) / 100,000 = 24. I'll buy that for the first approach where each byte is made a native 64-bit int. 3 * 8 bytes = 24 bytes. But for the third case where it's a single int? That makes no sense.

如果我错过了一些东西,请在这里输入代码:

Code here in case I missed something:

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;
        }
    }
}


推荐答案

由于在 int 中可以容纳四个个字节,因此可以使用单个 int 表示您的颜色(如果以后要添加例如alpha,则还有 byte 的余地)。示例的少量方法样本(未经测试,只是这样您就可以理解):

Since four bytes fit in an int, you could use a single int for your colors (and still have extra room for a byte if you want to add, say, alpha, later). Sample little group of methods (untested, just so you get the idea):

public int toIntColor(byte r, byte g, byte b) {
    int c = (int) r;
    c = (c << 8) | g;
    c = (c << 8) | b;
    return c;
}

然后将字节取回:

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;
}

这篇关于用Java存储颜色-byte; byte; byte vs. byte [3] vs int的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆