我正在编写一个大型应用程序,我试图尽可能多地保存内存并提高性能。因此,当我知道某个字段的值只有0 - 10或-100 - 100时,我会尝试使用short
数据类型而不是int
。
这对于其余代码来说意味着,当我调用这些函数时,我必须将简单的int
向下转换为short
s。例如:
方法签名
public void coordinates(short x, short y) ...
方法调用
obj.coordinates((short) 1, (short) 2);
就像我的代码中的所有代码一样,因为文字被视为int
,并且不会根据函数参数自动向下或输入。
因此,一旦这种向下转发发生,任何性能或内存增益是否真的显着?或者转换过程是如此有效,以至于我仍然可以获得一些收益?
答案 0 :(得分:10)
在32位平台上使用short与int没有性能优势,除了short []与int []之外的所有情况 - 即使这样,缺点通常也超过了专业人士。
假设你在x64,x86或ARM-32上运行:
在使用SHORTs与INTs时,您将看到的唯一好处是在您分配数组的情况下。在这种情况下, N 短路的数组大约是 N 整数数组的一半。
除了在大量短路中复杂但本地化数学的情况下将变量放在热循环中所带来的性能优势之外,您将永远看不到使用SHORTS与INT的好处。
在 ALL 其他情况下 - 例如用于字段,全局变量,参数和本地的短路,除了它可以存储的位数之外,还有否 SHORT和INT之间的区别。
我的建议一如既往地建议在使代码更难以阅读和更人为限制之前,尝试使用 BENCHMARKING 代码来查看内存和CPU瓶颈的位置,然后解决这些问题。
我强烈怀疑,如果你曾经遇到过你的应用程序遭受使用而不是短路的情况,那么你很快就会抛弃Java以获得更少的内存/ CPU饥饿运行时间,所以这项工作是预先付出的努力。
答案 1 :(得分:7)
据我所知,强制转换本身应该没有运行时成本(使用short
而不是int
实际上提高性能是有争议的,并且取决于应用程序的细节)。
请考虑以下事项:
public class Main {
public static void f(short x, short y) {
}
public static void main(String args[]) {
final short x = 1;
final short y = 2;
f(x, y);
f((short)1, (short)2);
}
}
main()
的最后两行编译为:
// f(x, y)
4: iconst_1
5: iconst_2
6: invokestatic #21 // Method f:(SS)V
// f((short)1, (short)2);
9: iconst_1
10: iconst_2
11: invokestatic #21 // Method f:(SS)V
如您所见,它们完全相同。演员阵容发生在编译时。
答案 2 :(得分:2)
从int
文字到short
的类型转换在编译时发生,并且没有运行时性能影响。
答案 3 :(得分:1)
您需要一种方法来检查类型选择对内存使用的影响。如果在给定情况下短路与整流将通过较低的内存占用来获得性能,那么对内存的影响应该是可测量的。
这是一种测量使用内存量的简单方法:
private static long inUseMemory() {
Runtime rt = Runtime.getRuntime();
rt.gc();
final long memory = rt.totalMemory() - rt.freeMemory();
return memory;
}
我还提供了一个程序示例,该程序使用该方法在某些常见情况下检查内存使用情况。分配一百万个短路阵列的内存增加证实了短阵列每个元素使用两个字节。各种对象数组的内存增加表明改变一个或两个字段的类型几乎没有区别。
这是一次运行的输出。 YMMV。
Before short[1000000] allocation: In use: 162608 Change 162608
After short[1000000] allocation: In use: 2162808 Change 2000200
After TwoShorts[1000000] allocation: In use: 34266200 Change 32103392
After NoShorts[1000000] allocation: In use: 58162560 Change 23896360
After TwoInts[1000000] allocation: In use: 90265920 Change 32103360
Dummy to keep arrays live -378899459
本文的其余部分是程序源:
public class Test {
private static int BIG = 1000000;
private static long oldMemory = 0;
public static void main(String[] args) {
short[] megaShort;
NoShorts[] megaNoShorts;
TwoShorts[] megaTwoShorts;
TwoInts[] megaTwoInts;
System.out.println("Before short[" + BIG + "] allocation: "
+ memoryReport());
megaShort = new short[BIG];
System.out
.println("After short[" + BIG + "] allocation: " + memoryReport());
megaTwoShorts = new TwoShorts[BIG];
for (int i = 0; i < BIG; i++) {
megaTwoShorts[i] = new TwoShorts();
}
System.out.println("After TwoShorts[" + BIG + "] allocation: "
+ memoryReport());
megaNoShorts = new NoShorts[BIG];
for (int i = 0; i < BIG; i++) {
megaNoShorts[i] = new NoShorts();
}
System.out.println("After NoShorts[" + BIG + "] allocation: "
+ memoryReport());
megaTwoInts = new TwoInts[BIG];
for (int i = 0; i < BIG; i++) {
megaTwoInts[i] = new TwoInts();
}
System.out.println("After TwoInts[" + BIG + "] allocation: "
+ memoryReport());
System.out.println("Dummy to keep arrays live "
+ (megaShort[0] + megaTwoShorts[0].hashCode() + megaNoShorts[0]
.hashCode() + megaTwoInts[0].hashCode()));
}
private static long inUseMemory() {
Runtime rt = Runtime.getRuntime();
rt.gc();
final long memory = rt.totalMemory() - rt.freeMemory();
return memory;
}
private static String memoryReport() {
long newMemory = inUseMemory();
String result = "In use: " + newMemory + " Change "
+ (newMemory - oldMemory);
oldMemory = newMemory;
return result;
}
}
class NoShorts {
//char a, b, c;
}
class TwoShorts {
//char a, b, c;
short s, t;
}
class TwoInts {
//char a, b, c;
int s, t;
}
答案 4 :(得分:-1)
首先,我想确认节省的内存,因为我看到了一些疑问。根据此处教程中short
的文档:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
短:短数据类型是16位带符号的二进制补码整数。它的最小值为-32,768,最大值为32,767(含)。与字节一样,适用相同的准则:在内存节省实际上很重要的情况下,您可以使用短路来节省大型阵列中的内存。
使用short
您确实将内存保存在大型数组中(希望是这种情况),因此最好使用它。
现在回答你的问题:
预测的性能/内存优势是否会因向下转换而无效?
简短回答是否。从int
向short
向下投射在编译时发生,因此从性能角度来看没有下降影响,但因为您正在保存内存,它可能会在内存阈值场景中带来更好的性能。