3

Below, you see a program that I wrote to see the state of different fields and memory allocations after calling requestObjectDeletion() method:

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);
    }
}

As far as I know,this method reclaims memory which is being used by “unreachable” objects. To be “unreachable”, an object can neither be pointed to by a static field nor by an object field. So calling requestObjectDeletion() in the above program reclaims the part of EEPROM that oldBuffer is refer to (As far as I know, oldBuffer is neither class field nor object field,right?). In this situation I expect that oldBuffer == null and therefore the JCRE must return 0x1111. But the output is 0x0000 unexpectedly :

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 : What can I conclude?

  • That part of memory is not reclaimed?
  • That part of memory is reclaimed but oldBuffer is a reference to it still?
  • something else?

Q2 : Is there any way to obtain the free memory size before and after of calling this method? (i.e. is there any method that return the size of free memory[not allocated]?)


Update 1 : Trying JCSystem.getAvailableMemory()

Based on @vojta answer, I changed my program in a way that the line byte[] oldBuffer = buffer; runs only once (using a flag named isFirstInvocation) and return the free available memory in two consecutive process() method invocation :

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);

    }
}

And this is the output :

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)

As both invocations return an equal value, I think the JCRE reclaims that part of memory immediately after calling requestObjectDeletion(), right?

Jean
  • 687
  • 1
  • 9
  • 25
  • Why do you sum availableMem1 and availableMem2? – vojta Mar 17 '15 at 14:29
  • @vojta I don't remember! give me some minutes! I think returning the sum of them is more reliable that returning availableMem1 only or availableMem2 only! – Jean Mar 17 '15 at 14:35
  • More reliable? Why? Your availableMem1 == 32767, your availableMem2 == 32767, together it is a negative number (short is signed) 0xFFFE, but I think all relevant information is gone. – vojta Mar 17 '15 at 14:39

1 Answers1

4

First of all, a rule based on my personal experience: if possible, do not use the garbage collector at all. GC is very slow and could be even dangerous (see Javacard - power loss during garbage collection).

Q1: If you really have to use GC, read the documentation:

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.

Shortly speaking, JCSystem.requestObjectDeletion(); has no immediate effect. That is why your local variable oldBuffer remains unchanged.

Q2: To find out how much persistent memory is available to your applet, use:

JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)

ANSWER to UPDATE 1: JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT) may be confusing for cards with more than 32767 bytes of persistent memory. Such cards usually offer their own proprietary ways to find out available memory.

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

Community
  • 1
  • 1
vojta
  • 5,591
  • 2
  • 24
  • 64
  • Thanks for your advice._JCRE schedule the object deletion service prior to the next invocation of the Applet.process() method._.OK. So if I add another flag to my program and run the line `byte[] oldBuffer = buffer;` in the first `process()` method invocation only, I must receive `0x0001` in second invocation? right? – Jean Mar 17 '15 at 12:49
  • Or I can use `JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)` in the start and end of `process()` method to compare the value of free memory in the **end of first invocation** with the free memory at the **start of second invocation** to see the `ObjectioDeletion` method, right? – Jean Mar 17 '15 at 12:52
  • Question updated. I used two variable named `availableMem1 ` and `availableMem2 ` in the start and end of `process()` method and return the sum of the at the end of this method. the returns are equal! I think this mean that `requestObjectDeletion()` method reclaim the memory immediately, right? (I changed initial value of static `buffer` also) – Jean Mar 17 '15 at 13:24
  • It's a JCOP with 64k EEPROM. So what now? I couldn't implement the first applet with `isFirstInvocation` flag (Because when I use `if (isFirstInvocation)`, the scope of `oldBuffer` is limited to this `if` scope and I can't change the value of `inNull` anymore). Do you have any idea? – Jean Mar 17 '15 at 14:29
  • @Jean What are you trying to do? To find a proof that GC works? Well I am quite sure it does - you can create longer arrays to get under 32767 remaining bytes... Your `oldBuffer` is always limited to `process` method. What is your goal? I see no difference, you can put the whole process method into if block. – vojta Mar 17 '15 at 14:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73172/discussion-between-vojta-and-jean). – vojta Mar 17 '15 at 14:41
  • I want to see if it works fine or not. I want to be sure that the oldBuffer change to `null`. I'll update the question and inform you. I don't want to put the whole process method into the `if (isFirstInvocation)` block! I want `if (oldBuffer == null) {isNull = true;} if (isNull) {ISOException.throwIt((short) 0x1111);} else {ISOException.throwIt((short) 0x0000);}` to be outside! – Jean Mar 17 '15 at 14:42