我正在用Java
7中的转义分析进行一些测试,以便更好地了解哪些对象可以进行堆栈分配。
这是我编写的用于测试堆栈分配的代码:
import java.util.ArrayList;
import java.util.Iterator;
public class EscapeAnalysis {
private static final long TIME_TO_TEST = 10L * 1000L; // 10s
static class Timestamp {
private long millis;
public Timestamp(long millis) {
this.millis = millis;
}
public long getTime() {
return millis;
}
public void setTime(long time) {
millis = time;
}
}
public static void main(String[] args) {
long r = 0;
System.out.println("test1");
r += test1();
System.out.println("test2");
r += test2();
System.out.println("test3");
r += test3();
System.out.println("test4");
r += test4();
System.out.println("test5");
r += test5();
System.out.println("test6");
r += test6();
System.out.println(r);
}
public static long test1() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
r += new Timestamp(System.currentTimeMillis()).getTime();
}
return r;
}
public static long test2() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
for (Iterator<Integer> it = l.iterator(); it.hasNext(); ) {
r += it.next().longValue();
}
}
return r;
}
public static long test3() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Timestamp ts = new Timestamp(System.currentTimeMillis());
ts.setTime(42);
r += ts.getTime();
}
return r;
}
public static long test4() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Iterator<Integer> it = l.iterator();
r += it.next().longValue();
r += it.next().longValue();
r += it.next().longValue();
r += it.next().longValue();
}
return r;
}
public static long test5() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Iterator<Integer> it = l.iterator();
for (int i = 0; i < l.size(); ++i) {
r += it.next().longValue();
}
}
return r;
}
public static long test6() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
for (Timestamp ts = new Timestamp(System.currentTimeMillis());
ts.getTime() > 0;
ts.setTime(ts.getTime() + System.currentTimeMillis())) {
r += ts.getTime();
}
}
return r;
}
}
这是它在Linux上与Java 7一起输出的结果
java -server -version
java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) 64-Bit Server VM (build 22.0-b10, mixed mode)
java -server -verbose:gc -XX:CompileThreshold=1 -cp bin EscapeAnalysis
test1
test2
[GC 15616K->352K(59776K), 0,0014270 secs]
[GC 15968K->288K(59776K), 0,0011790 secs]
[GC 15904K->288K(59776K), 0,0018170 secs]
[GC 15904K->288K(59776K), 0,0011100 secs]
[GC 15904K->288K(57152K), 0,0019790 secs]
[GC 15520K->320K(56896K), 0,0011670 secs]
[GC 15232K->284K(56256K), 0,0011440 secs]
test3
test4
test5
[GC 14876K->348K(55936K), 0,0005340 secs]
[GC 14620K->348K(56000K), 0,0004560 secs]
[GC 14300K->316K(55296K), 0,0004680 secs]
[GC 13948K->316K(55488K), 0,0003590 secs]
[GC 13692K->316K(54784K), 0,0004580 secs]
[GC 13436K->316K(54976K), 0,0005430 secs]
[GC 13180K->316K(54272K), 0,0004500 secs]
[GC 12924K->316K(54464K), 0,0005090 secs]
[GC 12668K->316K(53760K), 0,0004490 secs]
[GC 12412K->316K(53888K), 0,0004350 secs]
[GC 12156K->316K(53312K), 0,0005060 secs]
test6
6737499643744733086
我正在使用GC日志来了解是否在堆栈上分配了对象,这可能不是100%可靠的,但似乎给出了很好的提示。
基于输出,堆栈分配适用于test1,test3,test4和test6,不适用于test2和test5。我不明白为什么它在for循环中不适用于迭代器
我已经阅读了ArrayList迭代器的代码,但我不明白为什么它不符合测试2和5中的堆栈分配的条件,因为它既不逃避当前方法也不逃避当前线程。
任何想法?
EA是C2编译器根据它生成的IR进行分析的,因此您需要它才能在享受收益之前编译该方法。每个测试仅被调用一次,因此没有机会进行编译。热点内部Wiki中有关EA和C2
IR的详细信息(https://wiki.openjdk.java.net/display/HotSpot/Overview+of+Ideal、+C2%27s+high+level+intermediate+representation和https://wiki.openjdk.java.net/display/HotSpot/EscapeAnalysis)
这是一个试图显示影响的版本
import com.sun.management.ThreadMXBean;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Iterator;
public class EscapeAnalysisTest {
private static final long TIME_TO_TEST = 10L * 1000L; // 10s
static class Timestamp {
private long millis;
public Timestamp(long millis) {
this.millis = millis;
}
public long getTime() {
return millis;
}
public void setTime(long time) {
millis = time;
}
}
public static void main(String[] args) {
System.out.println("****");
doIt();
System.out.println("****");
doIt();
System.out.println("****");
doIt();
System.out.println("****");
doIt();
System.out.println("****");
}
private static void doIt() {
final ThreadMXBean mxbean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
final long tid = Thread.currentThread().getId();
long r = 0;
final long allocPre = mxbean.getThreadAllocatedBytes(tid);
r += test1();
long alloc1 = mxbean.getThreadAllocatedBytes(tid);
System.out.println("test1 - " + (alloc1 - allocPre));
r += test2();
final long alloc2 = mxbean.getThreadAllocatedBytes(tid);
System.out.println("test2 - " + (alloc2 - alloc1));
r += test3();
final long alloc3 = mxbean.getThreadAllocatedBytes(tid);
System.out.println("test3 - " + (alloc3 - alloc2));
r += test4();
final long alloc4 = mxbean.getThreadAllocatedBytes(tid);
System.out.println("test4 - " + (alloc4 - alloc3));
r += test5();
final long alloc5 = mxbean.getThreadAllocatedBytes(tid);
System.out.println("test5 - " + (alloc5 - alloc4));
r += test6();
final long alloc6 = mxbean.getThreadAllocatedBytes(tid);
System.out.println("test6 - " + (alloc6 - alloc5));
System.out.println(r);
}
public static long test1() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
r += new Timestamp(System.currentTimeMillis()).getTime();
}
return r;
}
public static long test2() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
for (Iterator<Integer> it = l.iterator(); it.hasNext(); ) {
r += it.next().longValue();
}
}
return r;
}
public static long test3() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Timestamp ts = new Timestamp(System.currentTimeMillis());
ts.setTime(42);
r += ts.getTime();
}
return r;
}
public static long test4() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Iterator<Integer> it = l.iterator();
r += it.next().longValue();
r += it.next().longValue();
r += it.next().longValue();
r += it.next().longValue();
}
return r;
}
public static long test5() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Iterator<Integer> it = l.iterator();
for (int i = 0; i < l.size(); ++i) {
r += it.next().longValue();
}
}
return r;
}
public static long test6() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
for (Timestamp ts = new Timestamp(System.currentTi());
ts.getTime() > 0;
ts.setTime(ts.getTime() + System.currentTimeMillis())) {
r += ts.getTime();
}
}
return r;
}
}
当运行时会生成以下输出 -server -XX:CompileThreshold=1
****
test1 - 109048
test2 - 89243416
test3 - 16664
test4 - 42840
test5 - 71982168
test6 - 1400
-5351026995119026839
****
test1 - 16432
test2 - 85921464
test3 - 16664
test4 - 42840
test5 - 66777600
test6 - 1368
7844020592566674506
****
test1 - 48
test2 - 18256
test3 - 272
test4 - 18264
test5 - 18264
test6 - 272
-2137858376905291730
****
test1 - 48
test2 - 18256
test3 - 272
test4 - 18264
test5 - 18264
test6 - 272
3273987624143297143
****
这里的一个危险是该方法的编译已从根本上改变了它,我没有尝试防止这种情况的发生,因此可能需要使用LogCompilation
或PrintCompilation
进行检查。
问题内容: 是局部变量,将其存储在堆或堆栈中的何处? 问题答案: 在堆上。每当您用来创建对象时,它都会在堆上分配。
我试图分析我的Java applet的堆转储,它耗尽了堆空间,即使我增加堆大小,如本文所示。applet:Java堆空间 今天上午我做了一些堆转储(是的...它可能做数字转储),我试图用MAT和Visual VM1.3.5来分析它们。运行泄漏测试后,主要的怀疑对象是org.eclipse.jdt.internal.core.javaModelManager和org.eclipse.jst.jee.
我试图了解分配给堆栈和堆的内存量。假设sizeof(char)=1字节,sizeof(void*)=4字节。给定以下代码: 我们被告知分配给堆的内存量是5个字节,我明白这确实是malloc(strlen(str2)=5)中的量。但是,我不明白的是分配给堆栈的内存量是如何达到18个字节的?我想如果他们给我们一个指针大小是4个字节的信息,那么我们有4个字节的指针str1和另外6个字节的数组str2(包
JVM规范(JSE 8版)提到: 第12页:2.5.2 JVM堆栈:“因为JVM堆栈除了用于推送和弹出帧之外,从来没有被直接操作过,所以帧可以被堆分配。” 第15页:2.6:帧:“帧是从创建帧的线程的JVM堆栈中分配的。”在第16页:“请注意,由线程创建的框架是该线程的本地框架,不能被任何其他线程引用。” 这听起来让我很困惑。既然一个帧是创建该帧的线程本地的,为什么要在堆中分配该帧,因为堆在所有J
问题内容: NumPy / SciPy或相关库中是否有类似Matlab的函数? 以供参考。Procrustes分析的目的是对齐2组点(换句话说,是2个形状),以通过消除缩放,平移和旋转扭曲分量来最小化它们之间的平方距离。 Matlab中的示例: NumPy中的相同任务: 注意:我只对对齐的形状感兴趣,因为平方误差(在Matlab代码中可变)很容易从2个形状中计算出来。 问题答案: 我不知道Pyth
考虑以下代码: 当 C2 OSR 编译开始时,热点 JVM 是否能够在堆栈上标量化 ?我想这可能是有问题的,因为活动对象已经存在于堆中,所以可能无法将对象从堆“移动”到堆栈和寄存器。