7

プロジェクト Lambdaの状態を説明する作業ドキュメントでは、いわゆる SAM (単一抽象メソッド) タイプについて言及しています。私が知る限り、現在のラムダの提案は、ラムダ式からこれらの型への自動変換を可能にすることにより、ランタイムだけに影響を与えることはありません。

理想的な状況では、SAM 型のインスタンスを内部的に関数ポインターで表すことができると思います。したがって、JVM はこれらのインスタンスのメモリ割り当てを回避できます。

最新の仮想マシンがそのような最適化を提供できるかどうか疑問に思っています.

4

2 に答える 2

6

@Tamásおそらく、BrianGoetzによるこのメーリングリストの投稿を読んでおく必要があります。

http://mail.openjdk.java.net/pipermail/lambda-dev/2011-August/003877.html

基本的に、ラムダ抽象化は現在オブジェクトを使用して実装されています。ただし、クラスのインスタンスよりも「小さい」ラムダの代替実現を可能にするように設計されています。

この状況は、自動ボクシングに似ていると考えることができます。intは整数にボックス化されますが、(intとして)「小さい」表現になります。

現在、ラムダはSAMタイプのインスタンスにボックス化する必要がありますが、b / c JVMには現在、ラムダをより小さな構成で表す方法がありません。将来的には、ラムダをオブジェクト以外のものとして表すことができる「プリミティブ関数」を含む新しいJVM標準が存在する可能性があります。

したがって、あなたの質問に答えるために、上記で提案したタイプの最適化は可能かもしれませんが、実装固有の機能ではなく、「プリミティブ関数」に関するJava8以降の作業が付属している可能性があります。

于 2011-08-19T15:46:48.240 に答える
5

単一のメソッド クラスを関数ポインターに変換するのは難しいことではありませんが、1 つ欠けていることがあります。ラムダ式は単なる関数ではなく、クロージャーです。違いは、クロージャが外部変数をキャプチャできることです。疑似 Java での次の例を検討してください。

public Adder makeAdder(double startNumber) {
    return #{ int number -> number + startNumber}
}

...

int startNumber = 5; 
Adder add5 = makeAdder(startNumber);
add5.invoke(4);  // ==> 9 

この例では、makeAdder() の呼び出しによって生成されるラムダ関数は、このラムダの外部で定義された変数を参照します。それが「クロージャー」と呼ばれる理由です。それらは、自由変数 (この場合は startNumber) に対して「閉じられています」。このような状況を処理するには、クロージャーは関数へのポインターとその環境へのポインターの両方を保持する必要があります。したがって、メソッドと少なくとも 1 つの変数を持つデータ構造が得られます。しかし、それは OOP でのオブジェクトの定義ではありませんか? では、匿名クラスのインスタンスにできるのであれば、新しい種類のオブジェクトを作成する理由は何ですか?

それでも、そのような匿名クラスに対して他の最適化が行われる場合があります。あなたが指摘した作業文書では、それらのいくつかについて言及しています。たとえば、最終的な変数を効果的に推論して使用しています(ただし、これは主に、コードを最適化するためではなく、原則として JVM でラムダを許可するために行われます)。生成された匿名クラスも最終的に実行される可能性があり、ほとんどの JVM は既に最終的な変数とクラスに対して優れた最適化を行っています。

その他の改善は、環境への参照にも関係する可能性があります。そこにはたくさんのオプションがあります。

于 2011-08-17T03:26:30.497 に答える