6

できるだけ多くのメモリを節約し、パフォーマンスを向上させようとしている大規模なアプリケーションを作成しています。そのため、0 ~ 10 または -100 ~ 100 の値しか持たないことがわかっているフィールドがある場合は、short代わりにデータ型を使用しようとしますint

ただし、コードの残りの部分でこれが意味することは、これらの関数を呼び出すときに、単純なints をshorts にダウンキャストする必要があるということです。例えば:

メソッド署名

public void coordinates(short x, short y) ...

メソッド呼び出し

obj.coordinates((short) 1, (short) 2);

intリテラルはs として扱われ、関数パラメーターに基づいて自動的にダウンキャストまたは型指定されないため、私のコード全体でそのようになっています。

そのため、このダウンキャストが発生すると、パフォーマンスやメモリの向上は実際に重要ですか? それとも、変換プロセスが効率的で、まだいくらかの利益を得ることができますか?

4

5 に答える 5

10

short[] と int[] の場合を除いて、32 ビット プラットフォームで short と int を使用してもパフォーマンス上の利点はありません。その場合でも、通常は短所が長所を上回ります。

x64、x86、または ARM-32 のいずれかで実行していると仮定します。

  • 使用中、16 ビットの SHORT は、int と同じように 32 ビットまたは 64 ビット長の整数レジスタに格納されます。つまり、short が使用されている場合、int に比べてメモリやパフォーマンスの利点は得られません。
  • スタック上にある場合、16 ビットの SHORT は 32 ビットまたは 64 ビットの「スロット」に格納され、スタックの整列を維持します (int と同様)。ローカル変数に INT に対して SHORT を使用しても、パフォーマンスやメモリの利点は得られません。
  • パラメーターとして渡される場合、SHORT はスタックにプッシュされるときに 32 ビットまたは 64 ビットに自動的に拡張されます (プッシュされたばかりの int とは異なります)。ここでのコードは、実際にはパフォーマンスがわずかに低下し、int を使用した場合よりも (コード) メモリ フットプリントがわずかに大きくなります。
  • グローバル (静的) 変数を格納する場合、これらの変数は自動的に拡張されて 32 ビットまたは 64 ビットのスロットを占有し、ポインター (参照) の配置が保証されます。つまり、グローバル (静的) 変数に INT を使用した場合と比較して、SHORT を使用した場合のパフォーマンスやメモリの利点は得られません。
  • フィールドを格納する場合、これらはクラスのレイアウトにマップされるヒープ メモリ内の構造に存在します。このクラスでは、フィールドは自動的に 32 ビットまたは 64 ビットにパディングされ、ヒープ上のフィールドの配置が維持されます。フィールドに対して INT に対して SHORT を使用しても、パフォーマンスやメモリの利点は得られません。

INT に対して SHORT を使用することで得られる唯一の利点は、それらの配列を割り当てる場合です。この場合、N short の配列は、N intの配列の約半分の長さになります。

short の大きな配列内で複雑だがローカライズされた数学の場合にホット ループ内に変数を一緒に配置することによって生じるパフォーマンス上の利点以外に、SHORT と INT を使用する利点は見られません。

フィールド、グローバル、パラメーター、およびローカルにショートが使用されている場合など、他のすべてのケースでは、格納できるビット数を除いて、ショートと INT の間に違いはありません。

いつものように、コードを読みにくくしたり人為的に制限したりする前に、コードのベンチマークを実行してメモリと CPU のボトルネックがどこにあるかを確認し、それらに取り組むことをお勧めします

アプリが short ではなく int の使用に苦しんでいるケースに出くわしたことがあるとしたら、とにかくメモリ/CPU を消費するランタイムを少なくするために Java を捨てて久しいので、このすべての作業を前もって行うことを強く疑っています。無駄な努力です。

于 2012-11-27T17:25:01.487 に答える
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()コンパイルの最後の2行は次のとおりです。

  // 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

ご覧のとおり、それらは同一です。キャストはコンパイル時に行われます。

于 2012-11-27T17:09:43.180 に答える
2

intリテラルからへの型キャストshortはコンパイル時に発生し、実行時のパフォーマンスへの影響はありません。

于 2012-11-27T17:09:23.293 に答える
1

メモリ使用量に対する型の選択の影響を確認する方法が必要です。特定の状況で short と int がメモリ フットプリントを削減することでパフォーマンスを向上させる場合、メモリへの影響は測定可能である必要があります。

使用中のメモリ量を測定する簡単な方法を次に示します。

      private static long inUseMemory() {
        Runtime rt = Runtime.getRuntime();
        rt.gc();
        final long memory = rt.totalMemory() - rt.freeMemory();
        return memory;
      }

また、その方法を使用して、いくつかの一般的な状況でメモリ使用量をチェックするプログラムの例も含めています。100 万の short の配列を割り当てるためのメモリの増加は、short 配列が要素ごとに 2 バイトを使用することを確認します。さまざまなオブジェクト配列のメモリの増加は、1 つまたは 2 つのフィールドの型を変更してもほとんど違いがないことを示しています。

これは、1 回の実行からの出力です。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;
    }
于 2012-11-27T17:54:20.350 に答える
-1

最初に、メモリの節約を確認したいと思います。shortここのチュートリアルのドキュメントに従って: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

short : short データ型は、16 ビットの符号付き 2 の補数整数です。最小値は -32,768 で、最大値は 32,767 (両端を含む) です。バイトと同様に、同じガイドラインが適用されます。メモリの節約が実際に重要な状況では、ショートを使用して大きな配列でメモリを節約できます。

を使用すると、メモリを大きな配列shortに保存できます(そうであることを願っています) 。したがって、それを使用することをお勧めします。

今あなたの質問に:

ショートのパフォーマンス/メモリの利点は、ダウンキャストによって無効になりますか?

簡単な答えはノーです。intからへのダウン キャストshortはコンパイル時に発生するため、パフォーマンスの観点からはダウン インパクトはありませんが、メモリを節約しているため、メモリしきい値のシナリオではパフォーマンスが向上する可能性があります

于 2012-11-27T17:05:38.893 に答える