3

メッセージの n 部分をバイト配列として含むマップを取得しました。最後のピースがマップに到達した後、メッセージを連結する必要があります。要件を満たす必要がある2つのソリューションが見つかりました。最初のものは System.arraycopy を使用しています:

public byte[] getMessageBytes() throws IOException {
    byte[] bytes = new byte[0];
    for (final Map.Entry<Short,byte[]> entry : myMap.entrySet()) {
        byte[] entryBytes = entry.getValue();
        byte[] temp = new byte[bytes.length + entryBytes.length];
        System.arraycopy(bytes, 0, temp, 0, bytes.length);
        System.arraycopy(entryBytes, 0, temp, bytes.length, entryBytes.length);
        bytes = temp;
    }
    return bytes;
}

2 つ目は ByteArrayOutputStream を使用しています。

public byte[] getMessageBytes() throws IOException {
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    for (final Map.Entry<Short,byte[]> entry : myMap.entrySet()) {
        baos.write(entry.getValue());
    }
    baos.flush();
    return baos.toByteArray();
}

パフォーマンスとメモリ使用量の観点から見たより良い方法は何ですか? さらに良い連結を行う別の方法はありますか?

4

6 に答える 6

9

断片の長さを合計することでメッセージのサイズを知ることができるので、私は次のようにします。

  1. ピースの長さを合計し、出力配列を割り当てます。
  2. arraycopy()出力配列の正しい位置に各ピースにループを使用します。

これは、メモリ効率が高く、高速である可能性があります。ただし、プロファイリングだけが全容を伝えることができます。

于 2012-05-02T14:56:23.573 に答える
4

これは、最初のバージョンよりもさらに優れたパフォーマンスを発揮するはずです (テストされていません)。

public byte[] getMessageBytes() throws IOException {
    long amount = 0L;
    long offset = 0L;
    // no reason to use entrySet() if you just use the values
    for (byte[] arr : myMap.values()) {
        amount += arr.length;
    }
    byte[] dest = new byte[amount];
    for (byte[] arr : myMap.values()) {
        System.arraycopy(arr, 0, dest, offset, arr.length);
        offset += arr.length;
    }
    return dest;
}

(この回答は aix のものとほぼ同じです)

于 2012-05-02T14:58:12.000 に答える
0

正しい答えは、特定の状況でテストして比較することです。

それは TreeMap のような SortedMap ですか、それとも実際にバイトをランダムにマージしていますか?

于 2012-05-02T14:56:14.617 に答える
0

最初にサイズを計算し、結果を 1 回割り当てることが、バイト配列を返すための最速のソリューションです。

結果のバイト配列を後で使用する場合InputStream、配列の結合サイズによっては、連結をまったく行わないのが最も速い方法かもしれません。その場合、SequenceInputStream複数のラッピングを作成できますByteArrayInputStreams。テストされていないサンプル コード:

Collection<byte[]> values = map.values();
List<ByteArrayInputStream> streams = new ArrayList<ByteArrayInputStream>(values.size());
for (byte[] bytes : values) {
    streams.add(new ByteArrayInputStream(bytes));
}
return new SequenceInputStream(Collections.enumeration(streams));
于 2012-05-02T16:22:45.657 に答える
0

反復ごとに新しい配列を作成する最初のソリューションは O(n^2) です。これは、多数のエントリがある場合に問題になります。さらに、それはかなり複雑です。

ByteArrayOutputStream を使用する方が 2 つの理由で優れています。O(n) で実行されることと、非常に単純です。

ほとんどの場合、少し速いのは、最初に合計サイズを計算してから、System.arraycopy を使用する場合です。しかし、ByteArrayOutputStream が本当に遅すぎる場合にのみそうします。

于 2012-05-02T15:03:37.793 に答える
0

これがネイティブコードです。

    /*
     * public static void arraycopy(Object src, int srcPos, Object dest,
     *      int destPos, int length)
     *
     * The description of this function is long, and describes a multitude
     * of checks and exceptions.
     */
    static void Dalvik_java_lang_System_arraycopy(const u4* args, JValue* pResult)
    {
        ArrayObject* srcArray = (ArrayObject*) args[0];
        int srcPos = args[1];
        ArrayObject* dstArray = (ArrayObject*) args[2];
        int dstPos = args[3];
        int length = args[4];
        /* Check for null pointers. */
        if (srcArray == NULL) {
            dvmThrowNullPointerException("src == null");
            RETURN_VOID();
        }
        if (dstArray == NULL) {
            dvmThrowNullPointerException("dst == null");
            RETURN_VOID();
        }
        /* Make sure source and destination are arrays. */
        if (!dvmIsArray(srcArray)) {
            dvmThrowArrayStoreExceptionNotArray(((Object*)srcArray)->clazz, "source");
            RETURN_VOID();
        }
        if (!dvmIsArray(dstArray)) {
            dvmThrowArrayStoreExceptionNotArray(((Object*)dstArray)->clazz, "destination");
            RETURN_VOID();
        }
        /* avoid int overflow */
        if (srcPos < 0 || dstPos < 0 || length < 0 ||
            srcPos > (int) srcArray->length - length ||
            dstPos > (int) dstArray->length - length)
        {
            dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
                "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
                srcArray->length, srcPos, dstArray->length, dstPos, length);
            RETURN_VOID();
        }
        ClassObject* srcClass = srcArray->clazz;
        ClassObject* dstClass = dstArray->clazz;
        char srcType = srcClass->descriptor[1];
        char dstType = dstClass->descriptor[1];
        /*
         * If one of the arrays holds a primitive type, the other array must
         * hold the same type.
         */
        bool srcPrim = (srcType != '[' && srcType != 'L');
        bool dstPrim = (dstType != '[' && dstType != 'L');
        if (srcPrim || dstPrim) {
            if (srcPrim != dstPrim || srcType != dstType) {
                dvmThrowArrayStoreExceptionIncompatibleArrays(srcClass, dstClass);
                RETURN_VOID();
            }
            if (false) ALOGD("arraycopy prim[%c] dst=%p %d src=%p %d len=%d",
                srcType, dstArray->contents, dstPos,
                srcArray->contents, srcPos, length);
            switch (srcType) {
            case 'B':
            case 'Z':
                /* 1 byte per element */
                memmove((u1*) dstArray->contents + dstPos,
                    (const u1*) srcArray->contents + srcPos,
                    length);
                break;
            case 'C':
            case 'S':
                /* 2 bytes per element */
                move16((u1*) dstArray->contents + dstPos * 2,
                    (const u1*) srcArray->contents + srcPos * 2,
                    length * 2);
                break;
            case 'F':
            case 'I':
                /* 4 bytes per element */
                move32((u1*) dstArray->contents + dstPos * 4,
                    (const u1*) srcArray->contents + srcPos * 4,
                    length * 4);
                break;
            case 'D':
            case 'J':
                /*
                 * 8 bytes per element.  We don't need to guarantee atomicity
                 * of the entire 64-bit word, so we can use the 32-bit copier.
                 */
                move32((u1*) dstArray->contents + dstPos * 8,
                    (const u1*) srcArray->contents + srcPos * 8,
                    length * 8);
                break;
            default:        /* illegal array type */
                ALOGE("Weird array type '%s'", srcClass->descriptor);
                dvmAbort();
            }
        } else {
            /*
             * Neither class is primitive.  See if elements in "src" are instances
             * of elements in "dst" (e.g. copy String to String or String to
             * Object).
             */
            const int width = sizeof(Object*);
            if (srcClass->arrayDim == dstClass->arrayDim &&
                dvmInstanceof(srcClass, dstClass))
            {
                /*
                 * "dst" can hold "src"; copy the whole thing.
                 */
                if (false) ALOGD("arraycopy ref dst=%p %d src=%p %d len=%d",
                    dstArray->contents, dstPos * width,
                    srcArray->contents, srcPos * width,
                    length * width);
                move32((u1*)dstArray->contents + dstPos * width,
                    (const u1*)srcArray->contents + srcPos * width,
                    length * width);
                dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
            } else {
                /*
                 * The arrays are not fundamentally compatible.  However, we
                 * may still be able to do this if the destination object is
                 * compatible (e.g. copy Object[] to String[], but the Object
                 * being copied is actually a String).  We need to copy elements
                 * one by one until something goes wrong.
                 *
                 * Because of overlapping moves, what we really want to do
                 * is compare the types and count up how many we can move,
                 * then call move32() to shift the actual data.  If we just
                 * start from the front we could do a smear rather than a move.
                 */
                Object** srcObj;
                int copyCount;
                ClassObject*   clazz = NULL;
                srcObj = ((Object**)(void*)srcArray->contents) + srcPos;
                if (length > 0 && srcObj[0] != NULL)
                {
                    clazz = srcObj[0]->clazz;
                    if (!dvmCanPutArrayElement(clazz, dstClass))
                        clazz = NULL;
                }
                for (copyCount = 0; copyCount < length; copyCount++)
                {
                    if (srcObj[copyCount] != NULL &&
                        srcObj[copyCount]->clazz != clazz &&
                        !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass))
                    {
                        /* can't put this element into the array */
                        break;
                    }
                }
                if (false) ALOGD("arraycopy iref dst=%p %d src=%p %d count=%d of %d",
                    dstArray->contents, dstPos * width,
                    srcArray->contents, srcPos * width,
                    copyCount, length);
                move32((u1*)dstArray->contents + dstPos * width,
                    (const u1*)srcArray->contents + srcPos * width,
                    copyCount * width);
                dvmWriteBarrierArray(dstArray, 0, copyCount);
                if (copyCount != length) {
                    dvmThrowArrayStoreExceptionIncompatibleArrayElement(srcPos + copyCount,
                            srcObj[copyCount]->clazz, dstClass);
                    RETURN_VOID();
                }
            }
        }
        RETURN_VOID();
    }
于 2020-06-22T13:09:40.177 に答える