有趣的主意。我认为确定此问题的更便捷的方法是实际衡量使用情况。示例程序:
public class FindMemoryUsage { public static void main(String[] args) { for (int i=0; i<50; i+=2) { long actual = getActualUsageForN(i); System.out.println(i + " = " + actual); long theoretical = getTheoreticalUsageForN(i); if (theoretical != actual) { throw new RuntimeException("Uh oh! Mismatch!"); } } } private static long getTheoreticalUsageForN(long count) { long optimal = (Unsafe.ARRAY_BYTE_base_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * count); return ((optimal - 1) & ~7) + 8; } private static long getActualUsageForN(int count) { System.gc(); byte[][] arrays = new byte[3000000][]; long begin = usedMemory(); for (int i=0; i<arrays.length; i++) { arrays[i] = new byte[count]; } long end = usedMemory(); return Math.round((end - begin) / (double) arrays.length); } private static long usedMemory() { return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); }}该程序为您提供此信息:
0 = 162 = 164 = 166 = 248 = 2410 = 2412 = 2414 = 3216 = 3218 = 3220 = 3222 = 4024 = 4026 = 4028 = 4030 = 4832 = 4834 = 4836 = 4838 = 5640 = 5642 = 5644 = 5646 = 6448 = 64
该数据来自使用率的实际计算和基于
sun.misc.Unsafe的常数和8字节舍入的理论使用率。这意味着您可以像建议的那样使用这些常量来“四舍五入”:
private static int roundSizeUp(int from) { long size = (Unsafe.ARRAY_BYTE_base_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * from); long actual = ((size - 1) & ~7) + 8; return (int) (actual - Unsafe.ARRAY_BYTE_base_OFFSET) / Unsafe.ARRAY_BYTE_INDEX_SCALE;}这是特定于VM的代码,但是
getActualUsageForN如果需要更多的可移植性,您可能可以根据该策略找到如何执行此操作。
请注意,这不是生产质量的代码:您需要仔细考虑溢出,并将
Unsafe引用更改为实际上适用于所使用数组类型的常量。



