Occupy.java 7.94 KB
Newer Older
konghaorui committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
package com.ydl.ydlnet.cache.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Chu on 2017/6/1.
 */

public class Occupy {
    //这8个方法不写不行,否则occupyof(int x)会自动重载到occupyof(Object o),并且无法在方法中判断
    public static int occupyof(boolean variable) {
        return 1;
    }

    public static int occupyof(byte variable) {
        return 1;
    }

    public static int occupyof(short variable) {
        return 2;
    }

    public static int occupyof(char variable) {
        return 2;
    }

    public static int occupyof(int variable) {
        return 4;
    }

    public static int occupyof(float variable) {
        return 4;
    }

    public static int occupyof(long variable) {
        return 8;
    }

    public static int occupyof(double variable) {
        return 8;
    }

    public Occupy(byte nullReferenceSize, byte emptyObjectSize, byte emptyArrayVarSize) {
        this.NULL_REFERENCE_SIZE = nullReferenceSize;
        this.EMPTY_OBJECT_SIZE = emptyObjectSize;
        this.EMPTY_ARRAY_VAR_SIZE = emptyArrayVarSize;
    }

    public static Occupy forJRockitVM() {
        return new Occupy((byte) 4, (byte) 8, (byte) 8);
    }

    public static Occupy forSun32BitsVM() {
        return new Occupy((byte) 4, (byte) 8, (byte) 4);
    }

    public static Occupy forSun64BitsVM() {
        return new Occupy((byte) 8, (byte) 16, (byte) 8);
    }

    public static Occupy forDetectedVM(){
        return null;
    }

    private final byte NULL_REFERENCE_SIZE;
    private final byte EMPTY_OBJECT_SIZE;
    private final byte EMPTY_ARRAY_VAR_SIZE;

    private static class ref{
        public ref(Object obj){
            this.obj = obj;
        }
        final Object obj;
        @Override
        public boolean equals(Object obj) {
            return (obj instanceof ref) && ((ref)obj).obj == this.obj;
        }
        @Override
        public int hashCode() {
            return obj.hashCode();
        }
    }

    private List dedup = new ArrayList();

    public int occupyof(Object object){
        dedup.clear();
        return occupyof0(object);
    }
    private int occupyof0(Object object) {
        if (object == null)
            return 0;
        ref r = new ref(object);
        if(dedup.contains(r))
            return 0;
        dedup.add(r);
        int varSize = 0;//对象中的值类型、引用类型变量大小
        int objSize = 0;//对象中的引用类型指向的对象实例的大小
        for (Class clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
//      System.out.println(clazz);
            if (clazz.isArray()) {//当前对象的数组
                varSize += EMPTY_ARRAY_VAR_SIZE;
                Class<?> componentType = clazz.getComponentType();
                if (componentType.isPrimitive()) {//当前数组是原生类型的数组
                    varSize += lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType);
                    return occupyOfSize(EMPTY_OBJECT_SIZE, varSize, 0);
                }
                Object[] array = (Object[]) object;
                varSize += NULL_REFERENCE_SIZE * array.length;//当前数组有length个引用,每个占用4字节
                for (Object o : array)
                    objSize += occupyof0(o);
                return occupyOfSize(EMPTY_OBJECT_SIZE, varSize, objSize);
            }
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isStatic(field.getModifiers()))
                    continue;//类成员不计
                //System.out.println(field.getDeclaringClass());
                if(clazz != field.getDeclaringClass())
                    continue;
                Class<?> type = field.getType();
                if (type.isPrimitive())
                    varSize += sizeofPrimitiveClass(type);
                else {
                    varSize += NULL_REFERENCE_SIZE;//一个引用型变量占用4个字节
                    try {
                        field.setAccessible(true);//可以访问非public类型的变量
                        objSize += occupyof0(field.get(object));
                    } catch (Exception e) {
                        objSize += occupyofConstructor(object, field);
                    }
                }
            }
        }
        return occupyOfSize(EMPTY_OBJECT_SIZE, varSize, objSize);
    }

    public static int sizeof(boolean variable) {
        return 1;
    }

    public static int sizeof(byte variable) {
        return 1;
    }

    public static int sizeof(short variable) {
        return 2;
    }

    public static int sizeof(char variable) {
        return 2;
    }

    public static int sizeof(int variable) {
        return 4;
    }

    public static int sizeof(float variable) {
        return 4;
    }

    public static int sizeof(long variable) {
        return 8;
    }

    public static int sizeof(double variable) {
        return 8;
    }


    public int sizeof(Object object) {
        if (object == null)
            return 0;
        int size = EMPTY_OBJECT_SIZE;
        Class clazz = object.getClass();
        if (clazz.isArray()) {
            size += EMPTY_ARRAY_VAR_SIZE;//length变量是int型
            Class<?> componentType = clazz.getComponentType();
            if (componentType.isPrimitive())
                return size + lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType);
            Object[] array = (Object[]) object;
            size += 4 * array.length;
            for (Object o : array)
                size += sizeof(o);
            return size;
        }
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers()))
                continue;//类成员不计
            Class<?> type = field.getType();
            if (type.isPrimitive())
                size += sizeofPrimitiveClass(type);
            else {
                size += 4;//一个引用型变量占用4个字节
                try {
                    field.setAccessible(true);//可以访问非public类型的变量
                    size += sizeof(field.get(object));
                } catch (Exception e) {
                    size += sizeofConstructor(object, field);
                }
            }
        }
        return size;
    }

    private static int occupyofConstructor(Object object, Field field) {
        throw new UnsupportedOperationException("field type Constructor not accessible: " + object.getClass() + " field:" + field);
    }

    private static int sizeofConstructor(Object object, Field field) {
        throw new UnsupportedOperationException("field type Constructor not accessible: " + object.getClass() + " field:" + field);
    }


    private static int occupyOfSize(int size) {
        return (size + 7) / 8 * 8;
    }

    private static int occupyOfSize(int selfSize, int varsSize, int objsSize) {
//    System.out.println("self=" + selfSize + " vars=" + varsSize + " objs=" + objsSize);
        return occupyOfSize(selfSize) + occupyOfSize(varsSize) + objsSize;
    }

    private static int sizeofPrimitiveClass(Class clazz) {
        return clazz == boolean.class || clazz == byte.class ? 1 : clazz == char.class || clazz == short.class ? 2 : clazz == int.class || clazz == float.class ? 4
                : 8;
    }

    private static int lengthOfPrimitiveArray(Object object) {
        Class<?> clazz = object.getClass();
        return clazz == boolean[].class ? ((boolean[]) object).length : clazz == byte[].class ? ((byte[]) object).length
                : clazz == char[].class ? ((char[]) object).length : clazz == short[].class ? ((short[]) object).length
                : clazz == int[].class ? ((int[]) object).length : clazz == float[].class ? ((float[]) object).length
                : clazz == long[].class ? ((long[]) object).length : ((double[]) object).length;
    }
}