NumPy中用flatten与ravel都能把数组拆成一维数组,两种方法有何区别? #
flatten()返回的是真实数据,需要分配新的内存空间。 ravel()函数返回的只是数组的视图。
在 Java 语言中,类是按需加载的。也就是对于一个 class 文件,只有当 hotspot 第一次使用它的时候,它才会被加载进来。假如我们在即时编译 A 方法的时候要调用 B 方法,但这时 B 方法还没有被加载进来,该怎么办呢?
虚拟机会采用一种叫做 patch code 的技术,在运行时再进行加载。简单地说,就是在生成 call 指令时候,它的目标地址填成一个虚拟机内部的用于解析符号的方法。在 CPU 执行这条 call 语句的时候,就会调用符号解析函数。此时虚拟机就会加载 B 方法所在的类,然后就能确定 B 方法的地址了,这时再把 B 方法的地址写回到 call 指令里。这个过程如下图所示:
这个过程很像是在给原始的代码打补丁,所以人们就把这种方式称为 patch code 技术。这就像是在原来的代码安装了一个机关,当 CPU 执行到这个机关时,就会触发一次符号的重定位,然后这个机关就被替换掉了。下一次 CPU 再执行到这个 call 指令的时候,就可以正常地调用到 B 方法了。
除 invokedynamic 外,其他的方法调用指令所消耗的操作数栈元素是根据调用类型以及目标方法描述符来确定的。在进行方法调用之前,程序需要依次压入调用者(invokestatic 不需要),以及各个参数。
public int neg(int i) {
return -i;
}
public int foo(int i) {
return neg(neg(i));
}
// foo方法对应的字节码如下:foo方法对应的字节码如下:
public int foo(int i);
0 aload_0 [this]
1 aload_0 [this]
2 iload_1 [i]
3 invokevirtual FooTest.neg(int) : int [25]
6 invokevirtual FooTest.neg(int) : int [25]
9 ireturn
以上面这段代码为例,当调用 foo(2) 时,每条指令执行前后局部变量数组空间以及操作数栈的分布如下所示:
数组相关指令,包括新建基本类型数组的 newarray,新建引用类型数组的 anewarray,生成多维数组的 multianewarray,以及求数组长度的 arraylength。另外,它还包括数组的加载指令以及存储指令。这些指令是区分类型的。例如, int 数组的加载指令为 iaload,存储指令为 iastore。