java 卡中的 ObjectDeletion 是如何工作的?

How ObjectDeletion works in java card?

下面,你看我写的一个程序,用来查看调用requestObjectDeletion()方法后不同字段的状态和内存分配:

public class ReqObjDel extends Applet {
    static byte[] buffer = new byte[2];
    static boolean isNull = false;

    private ReqObjDel() {
    }

    public static void install(byte bArray[], short bOffset, byte bLength)
            throws ISOException {
        new ReqObjDel().register();
    }

    public void process(APDU arg0) throws ISOException {
        if (selectingApplet()) {
            return;
        }

        if (buffer != null && (short) buffer.length == (short) 10) {
            return;
        }

        byte[] oldBuffer = buffer;
        buffer = new byte[10];

        JCSystem.requestObjectDeletion();

        if (oldBuffer == null)
            isNull = true;

        if (isNull) {
            ISOException.throwIt((short) 0x1111);
        } else
            ISOException.throwIt((short) 0x0000);
    }
}

据我所知,此方法回收“无法访问”的对象正在使用的内存。要“无法访问”,对象既不能被静态字段指向,也不能被对象字段指向。所以在上面的程序中调用 requestObjectDeletion() 回收了 oldBuffer 引用的 EEPROM 部分(据我所知, oldBuffer 既不是 class 字段也不是对象字段,对吧?)。在这种情况下,我预计 oldBuffer == null,因此 JCRE 必须 return 0x1111。但是输出意外地是 0x0000 :

OSC: opensc-tool -s 00a404000b0102030405060708090000 -s 00000000
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00
Received (SW1=0x00, SW2=0x00)

Q1 :我能得出什么结论?

Q2 :请问有什么方法可以获取调用此方法前后的空闲内存大小吗? (即是否有任何方法 return 空闲内存的大小 [未分配]?)


更新 1:尝试 JCSystem.getAvailableMemory()

根据@vojta 的回答,我更改了我的程序,使 byte[] oldBuffer = buffer; 行仅运行一次(使用名为 isFirstInvocation 的标志)和 return 可用内存在连续两次 process() 方法调用中:

public class ReqObjDel extends Applet {
    static byte[] buffer = new byte[10];
    static boolean isFirstInvocation = true;

    private ReqObjDel() {
    }

    public static void install(byte bArray[], short bOffset, byte bLength)
            throws ISOException {
        new ReqObjDel().register();
    }

    public void process(APDU arg0) throws ISOException {
        if (selectingApplet()) {
            return;
        }

        short availableMem1 = JCSystem
                .getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);

        if (isFirstInvocation) {

            byte[] oldBuffer = buffer;

            buffer = new byte[10];

            JCSystem.requestObjectDeletion();

            firstInvocation = false;
        }

        short availableMem2 = JCSystem
                .getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);

        short availableMemory = (short) (availableMem1 + availableMem2);
        ISOException.throwIt(availableMemory);

    }
}

这是输出:

OSC: osc -s 00a404000b0102030405060708090000 -s 00000000 -s 00000000
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00
Received (SW1=0xFF, SW2=0xFE)
Sending: 00 00 00 00
Received (SW1=0xFF, SW2=0xFE)

由于两个调用return 是一个相等的值,我认为 JCRE 在调用 requestObjectDeletion() 后立即回收了那部分内存,对吗?

首先,基于我个人经验的规则:如果可能,根本不要使用垃圾收集器。 GC 非常慢,甚至可能很危险(参见 )。

Q1: 如果你真的必须使用GC,请阅读文档:

This method is invoked by the applet to trigger the object deletion service of the Java Card runtime environment. If the Java Card runtime environment implements the object deletion mechanism, the request is merely logged at this time. The Java Card runtime environment must schedule the object deletion service prior to the next invocation of the Applet.process() method.

短期来说,JCSystem.requestObjectDeletion();没有立即生效。这就是为什么您的局部变量 oldBuffer 保持不变的原因。

Q2: 要了解有多少持久内存可供您的小程序使用,请使用:

JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)

更新 1 的答案: JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT) 对于永久内存超过 32767 字节的卡可能会造成混淆。这些卡通常提供自己的专有方法来查找可用内存。

If the number of available bytes is greater than 32767, then this method returns 32767.